From e895180388642ee6bcb9094d62699bc4e3bd84ae Mon Sep 17 00:00:00 2001 From: Leif Draven Date: Sun, 14 Sep 2025 22:50:22 +0900 Subject: [PATCH] Develop (#76) * refactor: rename queryannouncementhandler.go to queryAnnouncementLogic.go for clarity * feat(panDomain): update subscription logic to use V2 handler for improved functionality * refactor(subscribe): replace V2 handler with a unified Handler method for subscription logic * feat(subscribe): implement user agent limit feature with configurable list * fix(subscribe): improve error handling and logging for subscription requests * feat(subscribe): add user agent limit configuration to system settings * refactor(api): remove deprecated application-related endpoints and types * refactor(swagger): remove deprecated app.json generation from swagger configuration * refactor(swagger): remove deprecated app.json check from swagger configuration * fix(subscribe): update delete method to use Where clause for improved query accuracy * fix(subscribe): update Id field tag to use primaryKey and improve save method query * fix(subscribe): update Id field tag to use primaryKey and improve model queries * fix(subscribe): rename variable for clarity and add special handling for Stash user agent * fix(email): convert RegisterStartTime and RegisterEndTime to time.Time for accurate query filtering * refactor(log): consolidate logging models and update related logic for improved clarity and functionality * fix(types): change Content field type in MessageLog to interface{} for improved flexibility * fix(log): change MessageLog list to use value type for improved performance and memory efficiency * fix(email): set EmailTypeVerify in task payload and update content type conversion for verification email * fix(log): remove unused Id field from SystemLog during login log insertion * fix(login): remove debug logs and error logging during user login process * fix(log): add traffic reset logging for subscription resets * fix(log): insert reset traffic log during subscription activation * feat(log): add endpoints for retrieving and resetting subscribe traffic logs * refactor(log): remove Reset Subscribe Traffic Log endpoint and related types * feat(traffic): add traffic statistics logging and scheduling * fix(subscribe): ensure active status and reset timestamps during traffic resets * feat(api): enhance server and node management with new request/response structures * refactor(api): rename OnlineUser to ServerOnlineUser for clarity * feat(api): define OnlineUser type with SID and IP fields * feat(server): implement server management handlers and database schema * feat(api): add traffic log details filtering and enhance traffic log structures * feat(api): migrate server and node data handling, update related structures and logic * feat(server): implement server deletion logic with error handling * feat(api): update log filtering to use ResetSubscribe type for subscription logs * feat(api): standardize timestamp field across log structures * feat(api): refactor cache key handling for server and user lists * feat(api): enhance server status handling with protocol support and refactor related logic * fix(traffic): adjust start date for traffic statistics and improve log deletion comment * feat(api): implement daily traffic ranking for users and servers with error handling * feat(api): update server total data response to use 'OnlineUsers' and implement daily traffic statistics logging * feat(api): add log settings management with auto-clear and clear days configuration * fix(log): correct category in log settings update query * feat(routes): add handler for scheduled traffic statistics * feat(model): add user counts struct and update queries for new and renewal users * feat(api): add referral percentage and only first purchase fields to user model and requests * feat(database): update user table to add referral percentage and only first purchase fields * feat(api): add reset sort endpoints for server and node * feat(api): add sort field to server model * feat(api): implement sorting functionality for nodes and servers * fix(database): add sort column to nodes table * fix(model): enhance user statistics queries with new order and renewal order counts * fix(log): update timestamp handling in login and registration logs * fix(log): update sorting logic for server and user subscribe traffic logs * fix(server): add server status handling based on last reported time * fix(model): correct filter condition to use 'date' instead of 'data' * fix(migration): add index for traffic log on timestamp, user_id, and subscribe_id * fix(log): optimize user traffic rank data handling by using append instead of index assignment * fix(filter): refactor node list creation to use append and remove duplicates from tags * fix(node): add ServerId and Enabled fields to node update logic * feat(tags): add endpoint to query all node tags * fix(preview): add Preload parameter to FilterNodeList for improved data retrieval * fix(log): date is empty * feat(subscribe): add Language field to subscription models and update query logic * feat(subscription): add Language parameter to GetSubscription request and update query logic * fix(server): encode ServerKey in base64 and update last reported time for nodes * feat: delete common GetSubscription * feat(subscription): implement FilterList method for subscription queries and update related logic * fix(subscribe): remove duplicate user agents in SubscribeHandler * fix(push): initialize onlineUsers as a map in pushOnlineUsersLogic * fix(reset): initialize subs as a map in clearCache method * refactor(query): simplify node and tag filtering using InSet function * feat(userlist): enhance GetServerUserListLogic with improved node and tag handling * fix(userlist): correct node ID assignment and update query logic for tag filtering * fix(userlist): correct node ID assignment in getServerUserListLogic * refactor(query): streamline query construction for tag filtering * fix(statistics): optimize server ranking data handling in QueryServerTotalDataLogic * refactor(statistics): simplify server ranking data construction in QueryServerTotalDataLogic * fix(statistics): correct server traffic data assignment in QueryServerTotalDataLogic * fix(statistics): optimize yesterday's top 10 server traffic data assignment in QueryServerTotalDataLogic * fix(middleware): remove duplicate elements from user agent list in PanDomainMiddleware * feat(middleware): enhance user agent handling by querying client list in PanDomainMiddleware * feat(client): subscribe_template * feat(oauth): add user agent and IP logging to registration and login processes * fix(balance): add timestamp to balance logs for payment, refund, and recharge transactions * fix(log): correct comment for CommissionTypeRefund to improve clarity * fix(log): replace magic number with constant for gift type in purchase checkout logic * fix(log): rename OrderId to OrderNo for consistency in balance logging * feat(log): add logging for balance, gift amount, and commission adjustments * fix(user): correct placement of DeepCopy for user info update logic * feat(log): add UserSubscribeId to FilterSubscribeLogRequest for enhanced filtering * fix(purchase): streamline error handling and improve JSON marshaling for temporary orders * fix(order): simplify commission handling and improve payload parsing logic * fix(order): update commission calculation to actual payment amount minus gateway handling fee * feat(payment): add support for CryptoSaaS payment platform and enhance configuration handling * fix(balance): update QueryUserBalanceLog response structure to include balance log list * fix(email): update task progress handling to use specific task ID for updates * feat(quota): add quota task creation and querying endpoints with updated data structures * fix(email): update task handling to use generic task model and improve error logging * fix(order): improve error logging for database transaction and user cache updates * feat(quota): enhance quota task management with new request structures and processing logic * fix(quota): remove redundant quota task status endpoint from admin marketing routes * fix(worker): update task completion status handling in worker logic * fix(quota): update taskInfo to include current subscription count in quota logic * doc(log): rename function for clarity and add cache cleanup comment * fix(quota): update time handling in quota logic and correct subscriber ID query * fix(quota): update time handling to use UnixMilli for start time in quota logic * feat(protocol): add server protocol configuration query and enhance protocol options * fix(quota): correct time range queries for start and expire times in quota logic * fix(types): update plugin options to include 'none' in the plugin field --------- Co-authored-by: Chang lue Tsen --- .github/workflows/swagger.yaml | 2 - ...ld github.com_perfect-panel_server.run.xml | 3 - adapter/adapter.go | 109 +- adapter/client.go | 17 +- adapter/utils.go | 112 -- apis/admin/console.api | 2 +- apis/admin/log.api | 237 ++++- apis/admin/marketing.api | 79 +- apis/admin/server.api | 301 +++--- apis/admin/subscribe.api | 20 +- apis/admin/system.api | 84 -- apis/admin/user.api | 63 +- apis/app/announcement.api | 23 - apis/app/auth.api | 104 -- apis/app/document.api | 27 - apis/app/node.api | 40 - apis/app/order.api | 57 -- apis/app/payment.api | 23 - apis/app/subscribe.api | 65 -- apis/app/user.api | 86 -- apis/app/ws.api | 21 - apis/auth/auth.api | 3 + apis/common.api | 8 - apis/node/node.api | 21 + apis/public/portal.api | 5 +- apis/public/subscribe.api | 16 +- apis/public/user.api | 11 +- apis/swagger_app.api | 22 - apis/types.api | 163 +-- go.mod | 4 +- go.sum | 8 +- initialize/init.go | 1 - .../02101_subscribe_application.up.sql | 10 +- .../database/02102_subscribe_config.down.sql | 0 .../database/02102_subscribe_config.up.sql | 4 + .../02103_delete_application.down.sql | 0 .../database/02103_delete_application.up.sql | 3 + .../database/02104_system_log.down.sql | 106 ++ .../migrate/database/02104_system_log.up.sql | 19 + .../migrate/database/02105_node.down.sql | 2 + initialize/migrate/database/02105_node.up.sql | 28 + .../migrate/database/02106_subscribe.down.sql | 5 + .../migrate/database/02106_subscribe.up.sql | 7 + .../database/02107_log_setting.down.sql | 0 .../migrate/database/02107_log_setting.up.sql | 4 + .../database/02108_user_referral.down.sql | 3 + .../database/02108_user_referral.up.sql | 7 + .../migrate/database/02109_node_sort.down.sql | 2 + .../migrate/database/02109_node_sort.up.sql | 3 + .../database/02110_traffic_log_index.down.sql | 1 + .../database/02110_traffic_log_index.up.sql | 1 + .../database/02111_clear_table.down.sql | 2 + .../migrate/database/02111_clear_table.up.sql | 2 + .../migrate/database/02112_subscribe.down.sql | 0 .../migrate/database/02112_subscribe.up.sql | 7 + .../migrate/database/02113_task.down.sql | 0 initialize/migrate/database/02113_task.up.sql | 14 + initialize/migrate/migrate_test.go | 17 + initialize/statistics.go | 57 -- internal/config/cacheKey.go | 19 +- internal/config/config.go | 8 + .../log/filterBalanceLogHandler.go} | 14 +- .../log/filterCommissionLogHandler.go} | 14 +- .../log/filterEmailLogHandler.go} | 14 +- .../log/filterGiftLogHandler.go} | 14 +- .../log/filterLoginLogHandler.go} | 14 +- .../log/filterMobileLogHandler.go} | 14 +- .../log/filterRegisterLogHandler.go} | 14 +- .../log/filterResetSubscribeLogHandler.go | 26 + .../log/filterServerTrafficLogHandler.go} | 14 +- .../log/filterSubscribeLogHandler.go} | 14 +- .../log/filterTrafficLogDetailsHandler.go | 26 + .../filterUserSubscribeTrafficLogHandler.go | 26 + .../handler/admin/log/getLogSettingHandler.go | 18 + .../log/updateLogSettingHandler.go} | 14 +- .../admin/marketing/createQuotaTaskHandler.go | 26 + .../marketing/queryQuotaTaskListHandler.go} | 14 +- .../queryQuotaTaskPreCountHandler.go | 26 + .../marketing/queryQuotaTaskStatusHandler.go | 26 + .../server/batchDeleteNodeGroupHandler.go | 26 - .../handler/admin/server/createNodeHandler.go | 2 +- .../admin/server/createRuleGroupHandler.go | 26 - ...GroupHandler.go => createServerHandler.go} | 10 +- .../handler/admin/server/deleteNodeHandler.go | 2 +- ...eSortHandler.go => deleteServerHandler.go} | 10 +- ...ailHandler.go => filterNodeListHandler.go} | 10 +- .../admin/server/filterServerListHandler.go | 26 + ...andler.go => getServerProtocolsHandler.go} | 10 +- ...ndler.go => hasMigrateSeverNodeHandler.go} | 8 +- ...Handler.go => migrateServerNodeHandler.go} | 8 +- ...gListHandler.go => queryNodeTagHandler.go} | 8 +- ...Handler.go => resetSortWithNodeHandler.go} | 10 +- .../server/resetSortWithServerHandler.go | 26 + ...pHandler.go => toggleNodeStatusHandler.go} | 10 +- .../admin/server/updateNodeGroupHandler.go | 26 - .../handler/admin/server/updateNodeHandler.go | 2 +- .../admin/server/updateRuleGroupHandler.go | 26 - ...eNodeHandler.go => updateServerHandler.go} | 10 +- .../admin/system/createApplicationHandler.go | 26 - .../system/createApplicationVersionHandler.go | 26 - .../admin/system/deleteApplicationHandler.go | 26 - .../system/deleteApplicationVersionHandler.go | 26 - .../system/getApplicationConfigHandler.go | 18 - .../admin/system/getApplicationHandler.go | 18 - .../admin/system/getSubscribeTypeHandler.go | 18 - .../system/updateApplicationConfigHandler.go | 26 - .../admin/system/updateApplicationHandler.go | 26 - .../system/updateApplicationVersionHandler.go | 26 - ...getUserSubscribeResetTrafficLogsHandler.go | 26 + internal/handler/app/auth/loginHandler.go | 42 - internal/handler/app/auth/registerHandler.go | 43 - .../handler/app/auth/resetPasswordHandler.go | 41 - .../app/document/querydocumentlisthandler.go | 18 - .../app/node/getRuleGroupListHandler.go | 18 - internal/handler/app/order/purchasehandler.go | 26 - internal/handler/app/order/rechargehandler.go | 26 - internal/handler/app/order/renewalhandler.go | 26 - .../handler/app/order/resettraffichandler.go | 26 - .../getavailablepaymentmethodshandler.go | 18 - .../queryApplicationConfigHandler.go | 18 - .../querySubscribeGroupListHandler.go | 18 - .../subscribe/querySubscribeListHandler.go | 18 - .../queryUserAlreadySubscribeHandler.go | 18 - .../queryUserAvailableUserSubscribeHandler.go | 26 - .../resetUserSubscribePeriodHandler.go | 26 - .../handler/app/user/deleteAccountHandler.go | 26 - .../getuseronlinetimestatisticshandler.go | 18 - .../getusersubscribetrafficlogshandler.go | 26 - .../handler/app/user/queryUserInfoHandler.go | 18 - .../app/user/queryuseraffiliatehandler.go | 18 - .../handler/app/user/updatePasswordHandler.go | 26 - internal/handler/app/ws/appWsHandler.go | 20 - .../auth/telephoneUserRegisterHandler.go | 1 + internal/handler/auth/userRegisterHandler.go | 1 + .../handler/common/getApplicationHandler.go | 18 - .../handler/common/getSubscriptionHandler.go | 18 - .../handler/notify/paymentNotifyHandler.go | 2 +- .../public/portal/getSubscriptionHandler.go | 11 +- .../public/portal/purchaseCheckoutHandler.go | 2 +- .../queryApplicationConfigHandler.go | 18 - .../subscribe/querySubscribeListHandler.go | 12 +- internal/handler/routes.go | 322 ++---- .../queryServerProtocolConfigHandler.go | 41 + internal/handler/subscribe.go | 87 +- .../previewSubscribeTemplateLogic.go | 7 +- .../console/queryServerTotalDataLogic.go | 280 +++-- .../logic/admin/log/filterBalanceLogLogic.go | 64 ++ .../admin/log/filterCommissionLogLogic.go | 61 ++ .../logic/admin/log/filterEmailLogLogic.go | 68 ++ .../logic/admin/log/filterGiftLogLogic.go | 68 ++ .../logic/admin/log/filterLoginLogLogic.go | 65 ++ .../logic/admin/log/filterMobileLogLogic.go | 68 ++ .../logic/admin/log/filterRegisterLogLogic.go | 66 ++ .../admin/log/filterResetSubscribeLogLogic.go | 66 ++ .../admin/log/filterServerTrafficLogLogic.go | 166 +++ .../admin/log/filterSubscribeLogLogic.go | 71 ++ .../admin/log/filterTrafficLogDetailsLogic.go | 84 ++ .../log/filterUserSubscribeTrafficLogLogic.go | 160 +++ .../logic/admin/log/getLogSettingLogic.go | 37 + .../logic/admin/log/getMessageLogListLogic.go | 40 +- .../logic/admin/log/updateLogSettingLogic.go | 63 ++ .../createBatchSendEmailTaskLogic.go | 83 +- .../admin/marketing/createQuotaTaskLogic.go | 104 ++ .../getBatchSendEmailTaskListLogic.go | 43 +- .../getBatchSendEmailTaskStatusLogic.go | 6 +- .../marketing/getPreSendEmailCountLogic.go | 25 +- .../marketing/queryQuotaTaskListLogic.go | 83 ++ .../marketing/queryQuotaTaskPreCountLogic.go | 55 + .../marketing/queryQuotaTaskStatusLogic.go | 42 + .../marketing/stopBatchSendEmailTaskLogic.go | 2 +- .../admin/payment/createPaymentMethodLogic.go | 47 +- .../admin/payment/updatePaymentMethodLogic.go | 2 +- .../admin/server/batchDeleteNodeGroupLogic.go | 44 - .../admin/server/batchDeleteNodeLogic.go | 43 - internal/logic/admin/server/constant.go | 11 + .../admin/server/createNodeGroupLogic.go | 40 - .../logic/admin/server/createNodeLogic.go | 105 +- .../admin/server/createRuleGroupLogic.go | 78 -- .../logic/admin/server/createServerLogic.go | 111 ++ .../admin/server/deleteNodeGroupLogic.go | 44 - .../logic/admin/server/deleteNodeLogic.go | 30 +- ...RuleGroupLogic.go => deleteServerLogic.go} | 16 +- .../logic/admin/server/filterNodeListLogic.go | 64 ++ .../admin/server/filterServerListLogic.go | 164 +++ .../logic/admin/server/getNodeDetailLogic.go | 43 - .../admin/server/getNodeGroupListLogic.go | 39 - .../logic/admin/server/getNodeListLogic.go | 104 -- .../logic/admin/server/getNodeTagListLogic.go | 31 - .../admin/server/getRuleGroupListLogic.go | 54 - .../admin/server/getServerProtocolsLogic.go | 49 + .../admin/server/hasMigrateSeverNodeLogic.go | 52 + .../admin/server/migrateServerNodeLogic.go | 331 ++++++ .../logic/admin/server/queryNodeTagLogic.go | 46 + ...SortLogic.go => resetSortWithNodeLogic.go} | 35 +- .../admin/server/resetSortWithServerLogic.go | 86 ++ .../admin/server/toggleNodeStatusLogic.go | 43 + .../admin/server/updateNodeGroupLogic.go | 40 - .../logic/admin/server/updateNodeLogic.go | 117 +-- .../admin/server/updateRuleGroupLogic.go | 58 -- .../logic/admin/server/updateServerLogic.go | 115 +++ .../admin/subscribe/createSubscribeLogic.go | 6 +- .../subscribe/getSubscribeDetailsLogic.go | 5 +- .../admin/subscribe/getSubscribeListLogic.go | 17 +- .../admin/subscribe/subscribeSortLogic.go | 7 +- .../admin/subscribe/updateSubscribeLogic.go | 6 +- .../admin/system/createApplicationLogic.go | 125 --- .../system/createApplicationVersionLogic.go | 44 - .../admin/system/deleteApplicationLogic.go | 35 - .../system/deleteApplicationVersionLogic.go | 36 - .../admin/system/getApplicationConfigLogic.go | 49 - .../logic/admin/system/getApplicationLogic.go | 113 --- .../admin/system/getSubscribeTypeLogic.go | 42 - .../system/updateApplicationConfigLogic.go | 45 - .../admin/system/updateApplicationLogic.go | 149 --- .../system/updateApplicationVersionLogic.go | 45 - internal/logic/admin/user/createUserLogic.go | 10 +- internal/logic/admin/user/getUserListLogic.go | 12 +- .../logic/admin/user/getUserLoginLogsLogic.go | 28 +- .../admin/user/getUserSubscribeLogsLogic.go | 7 +- .../getUserSubscribeResetTrafficLogsLogic.go | 62 ++ .../admin/user/updateUserBasicInfoLogic.go | 87 +- .../announcement/queryAnnouncementLogic.go | 47 - internal/logic/app/auth/checkLogic.go | 41 - internal/logic/app/auth/findUserByMethod.go | 59 -- internal/logic/app/auth/getAppConfigLogic.go | 119 --- internal/logic/app/auth/loginLogic.go | 194 ---- internal/logic/app/auth/registerLogic.go | 249 ----- internal/logic/app/auth/resetPasswordLogic.go | 161 --- .../app/document/queryDocumentDetailLogic.go | 39 - .../app/document/queryDocumentListLogic.go | 48 - internal/logic/app/node/getNodeListLogic.go | 82 -- .../logic/app/node/getRuleGroupListLogic.go | 41 - internal/logic/app/order/calculateCoupon.go | 13 - internal/logic/app/order/calculateFee.go | 20 - .../logic/app/order/checkoutOrderLogic.go | 325 ------ internal/logic/app/order/closeOrderLogic.go | 186 ---- internal/logic/app/order/getDiscount.go | 14 - .../logic/app/order/preCreateOrderLogic.go | 123 --- internal/logic/app/order/purchaseLogic.go | 214 ---- .../logic/app/order/queryOrderDetailLogic.go | 40 - .../logic/app/order/queryOrderListLogic.go | 56 - internal/logic/app/order/rechargeLogic.go | 92 -- internal/logic/app/order/renewalLogic.go | 178 ---- internal/logic/app/order/resetTrafficLogic.go | 146 --- .../getAvailablePaymentMethodsLogic.go | 40 - .../subscribe/queryApplicationConfigLogic.go | 115 --- .../subscribe/querySubscribeGroupListLogic.go | 44 - .../app/subscribe/querySubscribeListLogic.go | 55 - .../queryUserAlreadySubscribeLogic.go | 67 -- .../queryUserAvailableUserSubscribeLogic.go | 107 -- .../resetUserSubscribePeriodLogic.go | 60 -- internal/logic/app/user/deleteAccountLogic.go | 103 -- .../user/getuseronlinetimestatisticslogic.go | 115 --- .../user/getusersubscribetrafficlogslogic.go | 85 -- .../app/user/queryUserAffiliateListLogic.go | 62 -- internal/logic/app/user/queryUserInfoLogic.go | 63 -- .../logic/app/user/queryuseraffiliatelogic.go | 60 -- .../logic/app/user/updatePasswordLogic.go | 46 - internal/logic/app/ws/appWsLogic.go | 81 -- .../auth/oauth/oAuthLoginGetTokenLogic.go | 100 +- internal/logic/auth/resetPasswordLogic.go | 22 +- internal/logic/auth/telephoneLoginLogic.go | 22 +- .../logic/auth/telephoneResetPasswordLogic.go | 26 + .../logic/auth/telephoneUserRegisterLogic.go | 48 + internal/logic/auth/userLoginLogic.go | 25 +- internal/logic/auth/userRegisterLogic.go | 43 +- internal/logic/common/getApplicationLogic.go | 136 --- internal/logic/common/getSubscriptionLogic.go | 41 - internal/logic/common/sendEmailCodeLogic.go | 34 +- .../logic/public/order/closeOrderLogic.go | 28 +- internal/logic/public/order/purchaseLogic.go | 27 +- internal/logic/public/order/renewalLogic.go | 27 +- .../logic/public/order/resetTrafficLogic.go | 27 +- .../public/portal/getSubscriptionLogic.go | 11 +- .../public/portal/purchaseCheckoutLogic.go | 114 ++- internal/logic/public/portal/purchaseLogic.go | 15 +- .../public/portal/queryPurchaseOrderLogic.go | 2 +- .../subscribe/queryApplicationConfigLogic.go | 116 --- .../subscribe/querySubscribeListLogic.go | 14 +- .../logic/public/user/getLoginLogLogic.go | 27 +- .../logic/public/user/getSubscribeLogLogic.go | 29 +- .../public/user/queryUserAffiliateLogic.go | 21 +- .../public/user/queryUserBalanceLogLogic.go | 50 +- .../user/queryUserCommissionLogLogic.go | 36 +- .../logic/public/user/unsubscribeLogic.go | 63 +- internal/logic/server/constant.go | 82 +- internal/logic/server/getServerConfigLogic.go | 176 +++- .../logic/server/getServerUserListLogic.go | 77 +- internal/logic/server/pushOnlineUsersLogic.go | 22 +- .../server/queryServerProtocolConfigLogic.go | 47 + .../logic/server/serverPushStatusLogic.go | 18 +- .../server/serverPushUserTrafficLogic.go | 28 +- internal/logic/subscribe/subscribeLogic.go | 372 +++---- internal/logic/subscribe/v2Logic.go | 127 --- internal/middleware/appMiddleware.go | 282 ------ internal/middleware/loggerMiddleware.go | 9 +- internal/middleware/panDomainMiddleware.go | 45 +- internal/middleware/traceMiddleware.go | 16 +- internal/model/application/application.go | 54 - internal/model/application/default.go | 245 ----- internal/model/application/model.go | 16 - internal/model/cache/constant.go | 52 - internal/model/cache/node.go | 584 ----------- internal/model/cache/node_test.go | 575 ----------- internal/model/cache/types.go | 34 - internal/model/client/application.go | 2 +- internal/model/client/default.go | 10 +- internal/model/log/default.go | 74 +- internal/model/log/log.go | 445 +++++++- internal/model/log/model.go | 58 +- internal/model/node/cache.go | 146 +++ internal/model/node/default.go | 131 +++ internal/model/node/model.go | 157 +++ internal/model/node/node.go | 82 ++ internal/model/node/server.go | 171 ++++ internal/model/order/model.go | 137 ++- internal/model/payment/payment.go | 69 +- internal/model/server/default.go | 13 +- internal/model/server/model.go | 7 +- internal/model/server/server.go | 1 + internal/model/subscribe/default.go | 55 +- internal/model/subscribe/model.go | 196 ++-- internal/model/subscribe/subscribe.go | 6 +- internal/model/subscribeType/default.go | 117 --- internal/model/subscribeType/model.go | 16 - internal/model/subscribeType/subscribeType.go | 15 - internal/model/system/model.go | 10 + internal/model/task/task.go | 166 ++- internal/model/user/default.go | 20 - internal/model/user/log.go | 81 -- internal/model/user/model.go | 194 +--- internal/model/user/subscribe.go | 8 +- internal/model/user/user.go | 101 +- internal/svc/serviceContext.go | 86 +- internal/types/types.go | 958 ++++++++++-------- pkg/constant/types.go | 20 +- pkg/email/worker.go | 66 +- pkg/orm/tool_test.go | 3 +- pkg/payment/platform.go | 13 +- pkg/tool/slice.go | 1 + pkg/tool/time.go | 7 + ppanel.api | 9 - queue/handler/routes.go | 7 + queue/logic/country/getCountryLogic.go | 38 - queue/logic/email/batchEmailLogic.go | 4 +- queue/logic/email/sendEmailLogic.go | 107 +- queue/logic/order/activateOrderLogic.go | 195 ++-- queue/logic/sms/sendSmsLogic.go | 19 +- .../subscription/checkSubscriptionLogic.go | 75 +- queue/logic/task/quotaLogic.go | 450 ++++++++ queue/logic/traffic/resetTrafficLogic.go | 132 ++- queue/logic/traffic/serverDataLogic.go | 4 +- queue/logic/traffic/trafficStatLogic.go | 176 ++++ queue/logic/traffic/trafficStatisticsLogic.go | 23 +- queue/types/email.go | 18 +- queue/types/scheduler.go | 1 + queue/types/sms.go | 2 +- queue/types/task.go | 9 + scheduler/scheduler.go | 16 +- 359 files changed, 9213 insertions(+), 12125 deletions(-) delete mode 100644 apis/app/announcement.api delete mode 100644 apis/app/auth.api delete mode 100644 apis/app/document.api delete mode 100644 apis/app/node.api delete mode 100644 apis/app/order.api delete mode 100644 apis/app/payment.api delete mode 100644 apis/app/subscribe.api delete mode 100644 apis/app/user.api delete mode 100644 apis/app/ws.api delete mode 100644 apis/swagger_app.api create mode 100644 initialize/migrate/database/02102_subscribe_config.down.sql create mode 100644 initialize/migrate/database/02102_subscribe_config.up.sql create mode 100644 initialize/migrate/database/02103_delete_application.down.sql create mode 100644 initialize/migrate/database/02103_delete_application.up.sql create mode 100644 initialize/migrate/database/02104_system_log.down.sql create mode 100644 initialize/migrate/database/02104_system_log.up.sql create mode 100644 initialize/migrate/database/02105_node.down.sql create mode 100644 initialize/migrate/database/02105_node.up.sql create mode 100644 initialize/migrate/database/02106_subscribe.down.sql create mode 100644 initialize/migrate/database/02106_subscribe.up.sql create mode 100644 initialize/migrate/database/02107_log_setting.down.sql create mode 100644 initialize/migrate/database/02107_log_setting.up.sql create mode 100644 initialize/migrate/database/02108_user_referral.down.sql create mode 100644 initialize/migrate/database/02108_user_referral.up.sql create mode 100644 initialize/migrate/database/02109_node_sort.down.sql create mode 100644 initialize/migrate/database/02109_node_sort.up.sql create mode 100644 initialize/migrate/database/02110_traffic_log_index.down.sql create mode 100644 initialize/migrate/database/02110_traffic_log_index.up.sql create mode 100644 initialize/migrate/database/02111_clear_table.down.sql create mode 100644 initialize/migrate/database/02111_clear_table.up.sql create mode 100644 initialize/migrate/database/02112_subscribe.down.sql create mode 100644 initialize/migrate/database/02112_subscribe.up.sql create mode 100644 initialize/migrate/database/02113_task.down.sql create mode 100644 initialize/migrate/database/02113_task.up.sql delete mode 100644 initialize/statistics.go rename internal/handler/{app/order/queryorderdetailhandler.go => admin/log/filterBalanceLogHandler.go} (58%) rename internal/handler/{app/document/querydocumentdetailhandler.go => admin/log/filterCommissionLogHandler.go} (56%) rename internal/handler/{app/order/queryorderlisthandler.go => admin/log/filterEmailLogHandler.go} (58%) rename internal/handler/{app/order/checkoutorderhandler.go => admin/log/filterGiftLogHandler.go} (57%) rename internal/handler/{app/order/precreateorderhandler.go => admin/log/filterLoginLogHandler.go} (58%) rename internal/handler/{app/node/getNodeListHandler.go => admin/log/filterMobileLogHandler.go} (56%) rename internal/handler/{app/announcement/queryannouncementhandler.go => admin/log/filterRegisterLogHandler.go} (55%) create mode 100644 internal/handler/admin/log/filterResetSubscribeLogHandler.go rename internal/handler/{app/user/queryuseraffiliatelisthandler.go => admin/log/filterServerTrafficLogHandler.go} (56%) rename internal/handler/{app/auth/getAppConfigHandler.go => admin/log/filterSubscribeLogHandler.go} (55%) create mode 100644 internal/handler/admin/log/filterTrafficLogDetailsHandler.go create mode 100644 internal/handler/admin/log/filterUserSubscribeTrafficLogHandler.go create mode 100644 internal/handler/admin/log/getLogSettingHandler.go rename internal/handler/{app/order/closeorderhandler.go => admin/log/updateLogSettingHandler.go} (57%) create mode 100644 internal/handler/admin/marketing/createQuotaTaskHandler.go rename internal/handler/{app/auth/checkHandler.go => admin/marketing/queryQuotaTaskListHandler.go} (53%) create mode 100644 internal/handler/admin/marketing/queryQuotaTaskPreCountHandler.go create mode 100644 internal/handler/admin/marketing/queryQuotaTaskStatusHandler.go delete mode 100644 internal/handler/admin/server/batchDeleteNodeGroupHandler.go delete mode 100644 internal/handler/admin/server/createRuleGroupHandler.go rename internal/handler/admin/server/{deleteNodeGroupHandler.go => createServerHandler.go} (66%) rename internal/handler/admin/server/{nodeSortHandler.go => deleteServerHandler.go} (68%) rename internal/handler/admin/server/{getNodeDetailHandler.go => filterNodeListHandler.go} (66%) create mode 100644 internal/handler/admin/server/filterServerListHandler.go rename internal/handler/admin/server/{getNodeListHandler.go => getServerProtocolsHandler.go} (64%) rename internal/handler/admin/server/{getNodeGroupListHandler.go => hasMigrateSeverNodeHandler.go} (53%) rename internal/handler/admin/server/{getRuleGroupListHandler.go => migrateServerNodeHandler.go} (54%) rename internal/handler/admin/server/{getNodeTagListHandler.go => queryNodeTagHandler.go} (58%) rename internal/handler/admin/server/{deleteRuleGroupHandler.go => resetSortWithNodeHandler.go} (66%) create mode 100644 internal/handler/admin/server/resetSortWithServerHandler.go rename internal/handler/admin/server/{createNodeGroupHandler.go => toggleNodeStatusHandler.go} (66%) delete mode 100644 internal/handler/admin/server/updateNodeGroupHandler.go delete mode 100644 internal/handler/admin/server/updateRuleGroupHandler.go rename internal/handler/admin/server/{batchDeleteNodeHandler.go => updateServerHandler.go} (66%) delete mode 100644 internal/handler/admin/system/createApplicationHandler.go delete mode 100644 internal/handler/admin/system/createApplicationVersionHandler.go delete mode 100644 internal/handler/admin/system/deleteApplicationHandler.go delete mode 100644 internal/handler/admin/system/deleteApplicationVersionHandler.go delete mode 100644 internal/handler/admin/system/getApplicationConfigHandler.go delete mode 100644 internal/handler/admin/system/getApplicationHandler.go delete mode 100644 internal/handler/admin/system/getSubscribeTypeHandler.go delete mode 100644 internal/handler/admin/system/updateApplicationConfigHandler.go delete mode 100644 internal/handler/admin/system/updateApplicationHandler.go delete mode 100644 internal/handler/admin/system/updateApplicationVersionHandler.go create mode 100644 internal/handler/admin/user/getUserSubscribeResetTrafficLogsHandler.go delete mode 100644 internal/handler/app/auth/loginHandler.go delete mode 100644 internal/handler/app/auth/registerHandler.go delete mode 100644 internal/handler/app/auth/resetPasswordHandler.go delete mode 100644 internal/handler/app/document/querydocumentlisthandler.go delete mode 100644 internal/handler/app/node/getRuleGroupListHandler.go delete mode 100644 internal/handler/app/order/purchasehandler.go delete mode 100644 internal/handler/app/order/rechargehandler.go delete mode 100644 internal/handler/app/order/renewalhandler.go delete mode 100644 internal/handler/app/order/resettraffichandler.go delete mode 100644 internal/handler/app/payment/getavailablepaymentmethodshandler.go delete mode 100644 internal/handler/app/subscribe/queryApplicationConfigHandler.go delete mode 100644 internal/handler/app/subscribe/querySubscribeGroupListHandler.go delete mode 100644 internal/handler/app/subscribe/querySubscribeListHandler.go delete mode 100644 internal/handler/app/subscribe/queryUserAlreadySubscribeHandler.go delete mode 100644 internal/handler/app/subscribe/queryUserAvailableUserSubscribeHandler.go delete mode 100644 internal/handler/app/subscribe/resetUserSubscribePeriodHandler.go delete mode 100644 internal/handler/app/user/deleteAccountHandler.go delete mode 100644 internal/handler/app/user/getuseronlinetimestatisticshandler.go delete mode 100644 internal/handler/app/user/getusersubscribetrafficlogshandler.go delete mode 100644 internal/handler/app/user/queryUserInfoHandler.go delete mode 100644 internal/handler/app/user/queryuseraffiliatehandler.go delete mode 100644 internal/handler/app/user/updatePasswordHandler.go delete mode 100644 internal/handler/app/ws/appWsHandler.go delete mode 100644 internal/handler/common/getApplicationHandler.go delete mode 100644 internal/handler/common/getSubscriptionHandler.go delete mode 100644 internal/handler/public/subscribe/queryApplicationConfigHandler.go create mode 100644 internal/handler/server/queryServerProtocolConfigHandler.go create mode 100644 internal/logic/admin/log/filterBalanceLogLogic.go create mode 100644 internal/logic/admin/log/filterCommissionLogLogic.go create mode 100644 internal/logic/admin/log/filterEmailLogLogic.go create mode 100644 internal/logic/admin/log/filterGiftLogLogic.go create mode 100644 internal/logic/admin/log/filterLoginLogLogic.go create mode 100644 internal/logic/admin/log/filterMobileLogLogic.go create mode 100644 internal/logic/admin/log/filterRegisterLogLogic.go create mode 100644 internal/logic/admin/log/filterResetSubscribeLogLogic.go create mode 100644 internal/logic/admin/log/filterServerTrafficLogLogic.go create mode 100644 internal/logic/admin/log/filterSubscribeLogLogic.go create mode 100644 internal/logic/admin/log/filterTrafficLogDetailsLogic.go create mode 100644 internal/logic/admin/log/filterUserSubscribeTrafficLogLogic.go create mode 100644 internal/logic/admin/log/getLogSettingLogic.go create mode 100644 internal/logic/admin/log/updateLogSettingLogic.go create mode 100644 internal/logic/admin/marketing/createQuotaTaskLogic.go create mode 100644 internal/logic/admin/marketing/queryQuotaTaskListLogic.go create mode 100644 internal/logic/admin/marketing/queryQuotaTaskPreCountLogic.go create mode 100644 internal/logic/admin/marketing/queryQuotaTaskStatusLogic.go delete mode 100644 internal/logic/admin/server/batchDeleteNodeGroupLogic.go delete mode 100644 internal/logic/admin/server/batchDeleteNodeLogic.go create mode 100644 internal/logic/admin/server/constant.go delete mode 100644 internal/logic/admin/server/createNodeGroupLogic.go delete mode 100644 internal/logic/admin/server/createRuleGroupLogic.go create mode 100644 internal/logic/admin/server/createServerLogic.go delete mode 100644 internal/logic/admin/server/deleteNodeGroupLogic.go rename internal/logic/admin/server/{deleteRuleGroupLogic.go => deleteServerLogic.go} (50%) create mode 100644 internal/logic/admin/server/filterNodeListLogic.go create mode 100644 internal/logic/admin/server/filterServerListLogic.go delete mode 100644 internal/logic/admin/server/getNodeDetailLogic.go delete mode 100644 internal/logic/admin/server/getNodeGroupListLogic.go delete mode 100644 internal/logic/admin/server/getNodeListLogic.go delete mode 100644 internal/logic/admin/server/getNodeTagListLogic.go delete mode 100644 internal/logic/admin/server/getRuleGroupListLogic.go create mode 100644 internal/logic/admin/server/getServerProtocolsLogic.go create mode 100644 internal/logic/admin/server/hasMigrateSeverNodeLogic.go create mode 100644 internal/logic/admin/server/migrateServerNodeLogic.go create mode 100644 internal/logic/admin/server/queryNodeTagLogic.go rename internal/logic/admin/server/{nodeSortLogic.go => resetSortWithNodeLogic.go} (68%) create mode 100644 internal/logic/admin/server/resetSortWithServerLogic.go create mode 100644 internal/logic/admin/server/toggleNodeStatusLogic.go delete mode 100644 internal/logic/admin/server/updateNodeGroupLogic.go delete mode 100644 internal/logic/admin/server/updateRuleGroupLogic.go create mode 100644 internal/logic/admin/server/updateServerLogic.go delete mode 100644 internal/logic/admin/system/createApplicationLogic.go delete mode 100644 internal/logic/admin/system/createApplicationVersionLogic.go delete mode 100644 internal/logic/admin/system/deleteApplicationLogic.go delete mode 100644 internal/logic/admin/system/deleteApplicationVersionLogic.go delete mode 100644 internal/logic/admin/system/getApplicationConfigLogic.go delete mode 100644 internal/logic/admin/system/getApplicationLogic.go delete mode 100644 internal/logic/admin/system/getSubscribeTypeLogic.go delete mode 100644 internal/logic/admin/system/updateApplicationConfigLogic.go delete mode 100644 internal/logic/admin/system/updateApplicationLogic.go delete mode 100644 internal/logic/admin/system/updateApplicationVersionLogic.go create mode 100644 internal/logic/admin/user/getUserSubscribeResetTrafficLogsLogic.go delete mode 100644 internal/logic/app/announcement/queryAnnouncementLogic.go delete mode 100644 internal/logic/app/auth/checkLogic.go delete mode 100644 internal/logic/app/auth/findUserByMethod.go delete mode 100644 internal/logic/app/auth/getAppConfigLogic.go delete mode 100644 internal/logic/app/auth/loginLogic.go delete mode 100644 internal/logic/app/auth/registerLogic.go delete mode 100644 internal/logic/app/auth/resetPasswordLogic.go delete mode 100644 internal/logic/app/document/queryDocumentDetailLogic.go delete mode 100644 internal/logic/app/document/queryDocumentListLogic.go delete mode 100644 internal/logic/app/node/getNodeListLogic.go delete mode 100644 internal/logic/app/node/getRuleGroupListLogic.go delete mode 100644 internal/logic/app/order/calculateCoupon.go delete mode 100644 internal/logic/app/order/calculateFee.go delete mode 100644 internal/logic/app/order/checkoutOrderLogic.go delete mode 100644 internal/logic/app/order/closeOrderLogic.go delete mode 100644 internal/logic/app/order/getDiscount.go delete mode 100644 internal/logic/app/order/preCreateOrderLogic.go delete mode 100644 internal/logic/app/order/purchaseLogic.go delete mode 100644 internal/logic/app/order/queryOrderDetailLogic.go delete mode 100644 internal/logic/app/order/queryOrderListLogic.go delete mode 100644 internal/logic/app/order/rechargeLogic.go delete mode 100644 internal/logic/app/order/renewalLogic.go delete mode 100644 internal/logic/app/order/resetTrafficLogic.go delete mode 100644 internal/logic/app/payment/getAvailablePaymentMethodsLogic.go delete mode 100644 internal/logic/app/subscribe/queryApplicationConfigLogic.go delete mode 100644 internal/logic/app/subscribe/querySubscribeGroupListLogic.go delete mode 100644 internal/logic/app/subscribe/querySubscribeListLogic.go delete mode 100644 internal/logic/app/subscribe/queryUserAlreadySubscribeLogic.go delete mode 100644 internal/logic/app/subscribe/queryUserAvailableUserSubscribeLogic.go delete mode 100644 internal/logic/app/subscribe/resetUserSubscribePeriodLogic.go delete mode 100644 internal/logic/app/user/deleteAccountLogic.go delete mode 100644 internal/logic/app/user/getuseronlinetimestatisticslogic.go delete mode 100644 internal/logic/app/user/getusersubscribetrafficlogslogic.go delete mode 100644 internal/logic/app/user/queryUserAffiliateListLogic.go delete mode 100644 internal/logic/app/user/queryUserInfoLogic.go delete mode 100644 internal/logic/app/user/queryuseraffiliatelogic.go delete mode 100644 internal/logic/app/user/updatePasswordLogic.go delete mode 100644 internal/logic/app/ws/appWsLogic.go delete mode 100644 internal/logic/common/getApplicationLogic.go delete mode 100644 internal/logic/common/getSubscriptionLogic.go delete mode 100644 internal/logic/public/subscribe/queryApplicationConfigLogic.go create mode 100644 internal/logic/server/queryServerProtocolConfigLogic.go delete mode 100644 internal/logic/subscribe/v2Logic.go delete mode 100644 internal/middleware/appMiddleware.go delete mode 100644 internal/model/application/application.go delete mode 100644 internal/model/application/default.go delete mode 100644 internal/model/application/model.go delete mode 100644 internal/model/cache/constant.go delete mode 100644 internal/model/cache/node.go delete mode 100644 internal/model/cache/node_test.go delete mode 100644 internal/model/cache/types.go create mode 100644 internal/model/node/cache.go create mode 100644 internal/model/node/default.go create mode 100644 internal/model/node/model.go create mode 100644 internal/model/node/node.go create mode 100644 internal/model/node/server.go delete mode 100644 internal/model/subscribeType/default.go delete mode 100644 internal/model/subscribeType/model.go delete mode 100644 internal/model/subscribeType/subscribeType.go delete mode 100644 internal/model/user/log.go create mode 100644 queue/logic/task/quotaLogic.go create mode 100644 queue/logic/traffic/trafficStatLogic.go create mode 100644 queue/types/task.go diff --git a/.github/workflows/swagger.yaml b/.github/workflows/swagger.yaml index 9ddeff2..177c2b0 100644 --- a/.github/workflows/swagger.yaml +++ b/.github/workflows/swagger.yaml @@ -35,7 +35,6 @@ jobs: mkdir -p swagger goctl api plugin -plugin goctl-swagger='swagger -filename common.json -pack Response -response "[{\"name\":\"code\",\"type\":\"integer\",\"description\":\"状态码\"},{\"name\":\"msg\",\"type\":\"string\",\"description\":\"消息\"},{\"name\":\"data\",\"type\":\"object\",\"description\":\"数据\",\"is_data\":true}]";' -api ./apis/swagger_common.api -dir ./swagger goctl api plugin -plugin goctl-swagger='swagger -filename user.json -pack Response -response "[{\"name\":\"code\",\"type\":\"integer\",\"description\":\"状态码\"},{\"name\":\"msg\",\"type\":\"string\",\"description\":\"消息\"},{\"name\":\"data\",\"type\":\"object\",\"description\":\"数据\",\"is_data\":true}]";' -api ./apis/swagger_user.api -dir ./swagger - goctl api plugin -plugin goctl-swagger='swagger -filename app.json -pack Response -response "[{\"name\":\"code\",\"type\":\"integer\",\"description\":\"状态码\"},{\"name\":\"msg\",\"type\":\"string\",\"description\":\"消息\"},{\"name\":\"data\",\"type\":\"object\",\"description\":\"数据\",\"is_data\":true}]";' -api ./apis/swagger_app.api -dir ./swagger goctl api plugin -plugin goctl-swagger='swagger -filename admin.json -pack Response -response "[{\"name\":\"code\",\"type\":\"integer\",\"description\":\"状态码\"},{\"name\":\"msg\",\"type\":\"string\",\"description\":\"消息\"},{\"name\":\"data\",\"type\":\"object\",\"description\":\"数据\",\"is_data\":true}]";' -api ./apis/swagger_admin.api -dir ./swagger goctl api plugin -plugin goctl-swagger='swagger -filename ppanel.json -pack Response -response "[{\"name\":\"code\",\"type\":\"integer\",\"description\":\"状态码\"},{\"name\":\"msg\",\"type\":\"string\",\"description\":\"消息\"},{\"name\":\"data\",\"type\":\"object\",\"description\":\"数据\",\"is_data\":true}]";' -api ppanel.api -dir ./swagger goctl api plugin -plugin goctl-swagger='swagger -filename node.json -pack Response -response "[{\"name\":\"code\",\"type\":\"integer\",\"description\":\"状态码\"},{\"name\":\"msg\",\"type\":\"string\",\"description\":\"消息\"},{\"name\":\"data\",\"type\":\"object\",\"description\":\"数据\",\"is_data\":true}]";' -api ./apis/swagger_node.api -dir ./swagger @@ -45,7 +44,6 @@ jobs: run: | test -f ./swagger/common.json test -f ./swagger/user.json - test -f ./swagger/app.json test -f ./swagger/admin.json - name: Checkout target repository diff --git a/.run/go build github.com_perfect-panel_server.run.xml b/.run/go build github.com_perfect-panel_server.run.xml index 454ba95..608afe7 100644 --- a/.run/go build github.com_perfect-panel_server.run.xml +++ b/.run/go build github.com_perfect-panel_server.run.xml @@ -3,9 +3,6 @@ - - - diff --git a/adapter/adapter.go b/adapter/adapter.go index 7dda13f..1acc674 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -1,26 +1,25 @@ package adapter import ( - "encoding/json" + "strings" - "github.com/perfect-panel/server/internal/model/server" + "github.com/perfect-panel/server/internal/model/node" "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/random" ) type Adapter struct { - SiteName string // 站点名称 - Servers []*server.Server // 服务器列表 - UserInfo User // 用户信息 - ClientTemplate string // 客户端配置模板 - OutputFormat string // 输出格式,默认是 base64 - SubscribeName string // 订阅名称 + SiteName string // 站点名称 + Servers []*node.Node // 服务器列表 + UserInfo User // 用户信息 + ClientTemplate string // 客户端配置模板 + OutputFormat string // 输出格式,默认是 base64 + SubscribeName string // 订阅名称 } type Option func(*Adapter) // WithServers 设置服务器列表 -func WithServers(servers []*server.Server) Option { +func WithServers(servers []*node.Node) Option { return func(opts *Adapter) { opts.Servers = servers } @@ -56,7 +55,7 @@ func WithSubscribeName(name string) Option { func NewAdapter(tpl string, opts ...Option) *Adapter { adapter := &Adapter{ - Servers: []*server.Server{}, + Servers: []*node.Node{}, UserInfo: User{}, ClientTemplate: tpl, OutputFormat: "base64", // 默认输出格式 @@ -87,51 +86,55 @@ func (adapter *Adapter) Client() (*Client, error) { return client, nil } -func (adapter *Adapter) Proxies(servers []*server.Server) ([]Proxy, error) { +func (adapter *Adapter) Proxies(servers []*node.Node) ([]Proxy, error) { var proxies []Proxy - for _, srv := range servers { - switch srv.RelayMode { - case server.RelayModeAll: - var relays []server.NodeRelay - if err := json.Unmarshal([]byte(srv.RelayNode), &relays); err != nil { - logger.Errorw("Unmarshal RelayNode", logger.Field("error", err.Error()), logger.Field("node", srv.Name), logger.Field("relayNode", srv.RelayNode)) - continue - } - for _, relay := range relays { - proxy, err := adapterProxy(*srv, relay.Host, uint64(relay.Port)) - if err != nil { - logger.Errorw("Adapter Proxy", logger.Field("error", err.Error()), logger.Field("node", srv.Name), logger.Field("relayNode", relay)) - continue - } - proxies = append(proxies, proxy) - } - case server.RelayModeRandom: - var relays []server.NodeRelay - if err := json.Unmarshal([]byte(srv.RelayNode), &relays); err != nil { - logger.Errorw("Unmarshal RelayNode", logger.Field("error", err.Error()), logger.Field("node", srv.Name), logger.Field("relayNode", srv.RelayNode)) - continue - } - randNum := random.RandomInRange(0, len(relays)-1) - relay := relays[randNum] - proxy, err := adapterProxy(*srv, relay.Host, uint64(relay.Port)) - if err != nil { - logger.Errorw("Adapter Proxy", logger.Field("error", err.Error()), logger.Field("node", srv.Name), logger.Field("relayNode", relay)) - continue - } - proxies = append(proxies, proxy) - - case server.RelayModeNone: - proxy, err := adapterProxy(*srv, srv.ServerAddr, 0) - if err != nil { - logger.Errorw("Adapter Proxy", logger.Field("error", err.Error()), logger.Field("node", srv.Name), logger.Field("serverAddr", srv.ServerAddr)) - continue - } - proxies = append(proxies, proxy) - default: - logger.Errorw("Unknown RelayMode", logger.Field("node", srv.Name), logger.Field("relayMode", srv.RelayMode)) + for _, item := range servers { + if item.Server == nil { + logger.Errorf("[Adapter] Server is nil for node ID: %d", item.Id) + continue + } + protocols, err := item.Server.UnmarshalProtocols() + if err != nil { + logger.Errorf("[Adapter] Unmarshal Protocols error: %s; server id : %d", err.Error(), item.ServerId) + continue + } + for _, protocol := range protocols { + if protocol.Type == item.Protocol { + proxies = append(proxies, Proxy{ + Sort: item.Sort, + Name: item.Name, + Server: item.Address, + Port: item.Port, + Type: item.Protocol, + Tags: strings.Split(item.Tags, ","), + Security: protocol.Security, + SNI: protocol.SNI, + AllowInsecure: protocol.AllowInsecure, + Fingerprint: protocol.Fingerprint, + RealityServerAddr: protocol.RealityServerAddr, + RealityServerPort: protocol.RealityServerPort, + RealityPrivateKey: protocol.RealityPrivateKey, + RealityPublicKey: protocol.RealityPublicKey, + RealityShortId: protocol.RealityShortId, + Transport: protocol.Transport, + Host: protocol.Host, + Path: protocol.Path, + ServiceName: protocol.ServiceName, + Method: protocol.Cipher, + ServerKey: protocol.ServerKey, + Flow: protocol.Flow, + HopPorts: protocol.HopPorts, + HopInterval: protocol.HopInterval, + ObfsPassword: protocol.ObfsPassword, + DisableSNI: protocol.DisableSNI, + ReduceRtt: protocol.ReduceRtt, + UDPRelayMode: protocol.UDPRelayMode, + CongestionController: protocol.CongestionController, + }) + } } - } + return proxies, nil } diff --git a/adapter/client.go b/adapter/client.go index 89c11ae..b1d16b7 100644 --- a/adapter/client.go +++ b/adapter/client.go @@ -11,9 +11,10 @@ import ( ) type Proxy struct { + Sort int Name string Server string - Port uint64 + Port uint16 Type string Tags []string @@ -33,20 +34,30 @@ type Proxy struct { Path string // For HTTP/HTTPS ServiceName string // For gRPC // Shadowsocks Options - Method string - ServerKey string // For Shadowsocks 2022 + Method string + ServerKey string // For Shadowsocks 2022 + Plugin string // Plugin for Shadowsocks + PluginOptions string // Plugin options for Shadowsocks // Vmess/Vless/Trojan Options Flow string // Flow for Vmess/Vless/Trojan // Hysteria2 Options HopPorts string // Comma-separated list of hop ports HopInterval int // Interval for hop ports in seconds ObfsPassword string // Obfuscation password for Hysteria2 + UpMbps int // Upload speed in Mbps + DownMbps int // Download speed in Mbps // Tuic Options DisableSNI bool // Disable SNI ReduceRtt bool // Reduce RTT UDPRelayMode string // UDP relay mode (e.g., "full", "partial") CongestionController string // Congestion controller (e.g., "cubic", "bbr") + + // AnyTLS + PaddingScheme string + + // Mieru + Multiplex string } type User struct { diff --git a/adapter/utils.go b/adapter/utils.go index dd87cf3..b8e8da3 100644 --- a/adapter/utils.go +++ b/adapter/utils.go @@ -1,113 +1 @@ package adapter - -import ( - "encoding/json" - "fmt" - "strings" - - "github.com/perfect-panel/server/internal/model/server" - "github.com/perfect-panel/server/pkg/tool" -) - -func adapterProxy(svr server.Server, host string, port uint64) (Proxy, error) { - tags := strings.Split(svr.Tags, ",") - if len(tags) > 0 { - tags = tool.RemoveDuplicateElements(tags...) - } - node := Proxy{ - Name: svr.Name, - Host: host, - Port: port, - Type: svr.Protocol, - Tags: tags, - } - switch svr.Protocol { - case "shadowsocks": - var ss server.Shadowsocks - if err := json.Unmarshal([]byte(svr.Config), &ss); err != nil { - return node, fmt.Errorf("unmarshal shadowsocks config: %v", err.Error()) - } - if port == 0 { - node.Port = uint64(ss.Port) - } - node.Method = ss.Method - node.ServerKey = ss.ServerKey - case "vless": - var vless server.Vless - if err := json.Unmarshal([]byte(svr.Config), &vless); err != nil { - return node, fmt.Errorf("unmarshal vless config: %v", err.Error()) - } - if port == 0 { - node.Port = uint64(vless.Port) - } - node.Flow = vless.Flow - node.Transport = vless.Transport - tool.DeepCopy(&node, vless.TransportConfig) - node.Security = vless.Security - tool.DeepCopy(&node, vless.SecurityConfig) - case "vmess": - var vmess server.Vmess - if err := json.Unmarshal([]byte(svr.Config), &vmess); err != nil { - return node, fmt.Errorf("unmarshal vmess config: %v", err.Error()) - } - if port == 0 { - node.Port = uint64(vmess.Port) - } - node.Flow = vmess.Flow - node.Transport = vmess.Transport - tool.DeepCopy(&node, vmess.TransportConfig) - node.Security = vmess.Security - tool.DeepCopy(&node, vmess.SecurityConfig) - case "trojan": - var trojan server.Trojan - if err := json.Unmarshal([]byte(svr.Config), &trojan); err != nil { - return node, fmt.Errorf("unmarshal trojan config: %v", err.Error()) - } - if port == 0 { - node.Port = uint64(trojan.Port) - - } - - node.Flow = trojan.Flow - node.Transport = trojan.Transport - tool.DeepCopy(&node, trojan.TransportConfig) - node.Security = trojan.Security - tool.DeepCopy(&node, trojan.SecurityConfig) - case "hysteria2": - var hysteria2 server.Hysteria2 - if err := json.Unmarshal([]byte(svr.Config), &hysteria2); err != nil { - return node, fmt.Errorf("unmarshal hysteria2 config: %v", err.Error()) - } - if port == 0 { - node.Port = uint64(hysteria2.Port) - } - node.HopPorts = hysteria2.HopPorts - node.HopInterval = hysteria2.HopInterval - node.ObfsPassword = hysteria2.ObfsPassword - tool.DeepCopy(&node, hysteria2.SecurityConfig) - case "tuic": - var tuic server.Tuic - if err := json.Unmarshal([]byte(svr.Config), &tuic); err != nil { - return node, fmt.Errorf("unmarshal tuic config: %v", err.Error()) - } - if port == 0 { - node.Port = uint64(tuic.Port) - } - node.DisableSNI = tuic.DisableSNI - node.ReduceRtt = tuic.ReduceRtt - node.UDPRelayMode = tuic.UDPRelayMode - node.CongestionController = tuic.CongestionController - case "anytls": - var anytls server.AnyTLS - if err := json.Unmarshal([]byte(svr.Config), &anytls); err != nil { - return node, fmt.Errorf("unmarshal anytls config: %v", err.Error()) - } - if port == 0 { - node.Port = uint64(anytls.Port) - } - tool.DeepCopy(&node, anytls.SecurityConfig) - default: - return node, fmt.Errorf("unsupported protocol: %s", svr.Protocol) - } - return node, nil -} diff --git a/apis/admin/console.api b/apis/admin/console.api index c20bb14..1a8ded7 100644 --- a/apis/admin/console.api +++ b/apis/admin/console.api @@ -21,7 +21,7 @@ type ( Download int64 `json:"download"` } ServerTotalDataResponse { - OnlineUserIPs int64 `json:"online_user_ips"` + OnlineUsers int64 `json:"online_users"` OnlineServers int64 `json:"online_servers"` OfflineServers int64 `json:"offline_servers"` TodayUpload int64 `json:"today_upload"` diff --git a/apis/admin/log.api b/apis/admin/log.api index 12fc312..3b117c8 100644 --- a/apis/admin/log.api +++ b/apis/admin/log.api @@ -12,19 +12,184 @@ import "../types.api" type ( GetMessageLogListRequest { - Page int `form:"page"` - Size int `form:"size"` - Type string `form:"type"` - Platform string `form:"platform,omitempty"` - To string `form:"to,omitempty"` - Subject string `form:"subject,omitempty"` - Content string `form:"content,omitempty"` - Status int `form:"status,omitempty"` + Page int `form:"page"` + Size int `form:"size"` + Type uint8 `form:"type"` + Search string `form:"search,optional"` } GetMessageLogListResponse { Total int64 `json:"total"` List []MessageLog `json:"list"` } + FilterLogParams { + Page int `form:"page"` + Size int `form:"size"` + Date string `form:"date,optional"` + Search string `form:"search,optional"` + } + FilterEmailLogResponse { + Total int64 `json:"total"` + List []MessageLog `json:"list"` + } + FilterMobileLogResponse { + Total int64 `json:"total"` + List []MessageLog `json:"list"` + } + SubscribeLog { + UserId int64 `json:"user_id"` + Token string `json:"token"` + UserAgent string `json:"user_agent"` + ClientIP string `json:"client_ip"` + UserSubscribeId int64 `json:"user_subscribe_id"` + Timestamp int64 `json:"timestamp"` + } + FilterSubscribeLogRequest { + FilterLogParams + UserId int64 `form:"user_id,optional"` + UserSubscribeId int64 `form:"user_subscribe_id,optional"` + } + FilterSubscribeLogResponse { + Total int64 `json:"total"` + List []SubscribeLog `json:"list"` + } + LoginLog { + UserId int64 `json:"user_id"` + Method string `json:"method"` + LoginIP string `json:"login_ip"` + UserAgent string `json:"user_agent"` + Success bool `json:"success"` + Timestamp int64 `json:"timestamp"` + } + FilterLoginLogRequest { + FilterLogParams + UserId int64 `form:"user_id,optional"` + } + FilterLoginLogResponse { + Total int64 `json:"total"` + List []LoginLog `json:"list"` + } + RegisterLog { + UserId int64 `json:"user_id"` + AuthMethod string `json:"auth_method"` + Identifier string `json:"identifier"` + RegisterIP string `json:"register_ip"` + UserAgent string `json:"user_agent"` + Timestamp int64 `json:"timestamp"` + } + FilterRegisterLogRequest { + FilterLogParams + UserId int64 `form:"user_id,optional"` + } + FilterRegisterLogResponse { + Total int64 `json:"total"` + List []RegisterLog `json:"list"` + } + ResetSubscribeLog { + Type uint16 `json:"type"` + UserId int64 `json:"user_id"` + UserSubscribeId int64 `json:"user_subscribe_id"` + OrderNo string `json:"order_no,omitempty"` + Timestamp int64 `json:"timestamp"` + } + FilterResetSubscribeLogRequest { + FilterLogParams + UserSubscribeId int64 `form:"user_subscribe_id,optional"` + } + FilterResetSubscribeLogResponse { + Total int64 `json:"total"` + List []ResetSubscribeLog `json:"list"` + } + UserSubscribeTrafficLog { + SubscribeId int64 `json:"subscribe_id"` // Subscribe ID + UserId int64 `json:"user_id"` // User ID + Upload int64 `json:"upload"` // Upload traffic in bytes + Download int64 `json:"download"` // Download traffic in bytes + Total int64 `json:"total"` // Total traffic in bytes (Upload + Download) + Date string `json:"date"` // Date in YYYY-MM-DD format + Details bool `json:"details"` // Whether to show detailed traffic + } + FilterSubscribeTrafficRequest { + FilterLogParams + UserId int64 `form:"user_id,optional"` + UserSubscribeId int64 `form:"user_subscribe_id,optional"` + } + FilterSubscribeTrafficResponse { + Total int64 `json:"total"` + List []UserSubscribeTrafficLog `json:"list"` + } + ServerTrafficLog { + ServerId int64 `json:"server_id"` // Server ID + Upload int64 `json:"upload"` // Upload traffic in bytes + Download int64 `json:"download"` // Download traffic in bytes + Total int64 `json:"total"` // Total traffic in bytes (Upload + Download) + Date string `json:"date"` // Date in YYYY-MM-DD format + Details bool `json:"details"` // Whether to show detailed traffic + } + FilterServerTrafficLogRequest { + FilterLogParams + ServerId int64 `form:"server_id,optional"` + } + FilterServerTrafficLogResponse { + Total int64 `json:"total"` + List []ServerTrafficLog `json:"list"` + } + FilterBalanceLogRequest { + FilterLogParams + UserId int64 `form:"user_id,optional"` + } + FilterBalanceLogResponse { + Total int64 `json:"total"` + List []BalanceLog `json:"list"` + } + FilterCommissionLogRequest { + FilterLogParams + UserId int64 `form:"user_id,optional"` + } + FilterCommissionLogResponse { + Total int64 `json:"total"` + List []CommissionLog `json:"list"` + } + GiftLog { + Type uint16 `json:"type"` + userId int64 `json:"user_id"` + OrderNo string `json:"order_no"` + SubscribeId int64 `json:"subscribe_id"` + Amount int64 `json:"amount"` + Balance int64 `json:"balance"` + Remark string `json:"remark,omitempty"` + Timestamp int64 `json:"timestamp"` + } + FilterGiftLogRequest { + FilterLogParams + UserId int64 `form:"user_id,optional"` + } + FilterGiftLogResponse { + Total int64 `json:"total"` + List []GiftLog `json:"list"` + } + TrafficLogDetails { + Id int64 `json:"id"` + ServerId int64 `json:"server_id"` + UserId int64 `json:"user_id"` + SubscribeId int64 `json:"subscribe_id"` + Download int64 `json:"download"` + Upload int64 `json:"upload"` + Timestamp int64 `json:"timestamp"` + } + FilterTrafficLogDetailsRequest { + FilterLogParams + ServerId int64 `form:"server_id,optional"` + SubscribeId int64 `form:"subscribe_id,optional"` + UserId int64 `form:"user_id,optional"` + } + FilterTrafficLogDetailsResponse { + Total int64 `json:"total"` + List []TrafficLogDetails `json:"list"` + } + LogSetting { + AutoClear *bool `json:"auto_clear"` + ClearDays int64 `json:"clear_days"` + } ) @server ( @@ -36,5 +201,61 @@ service ppanel { @doc "Get message log list" @handler GetMessageLogList get /message/list (GetMessageLogListRequest) returns (GetMessageLogListResponse) + + @doc "Filter email log" + @handler FilterEmailLog + get /email/list (FilterLogParams) returns (FilterEmailLogResponse) + + @doc "Filter mobile log" + @handler FilterMobileLog + get /mobile/list (FilterLogParams) returns (FilterMobileLogResponse) + + @doc "Filter subscribe log" + @handler FilterSubscribeLog + get /subscribe/list (FilterSubscribeLogRequest) returns (FilterSubscribeLogResponse) + + @doc "Filter login log" + @handler FilterLoginLog + get /login/list (FilterLoginLogRequest) returns (FilterLoginLogResponse) + + @doc "Filter register log" + @handler FilterRegisterLog + get /register/list (FilterRegisterLogRequest) returns (FilterRegisterLogResponse) + + @doc "Filter reset subscribe log" + @handler FilterResetSubscribeLog + get /subscribe/reset/list (FilterResetSubscribeLogRequest) returns (FilterResetSubscribeLogResponse) + + @doc "Filter user subscribe traffic log" + @handler FilterUserSubscribeTrafficLog + get /subscribe/traffic/list (FilterSubscribeTrafficRequest) returns (FilterSubscribeTrafficResponse) + + @doc "Filter server traffic log" + @handler FilterServerTrafficLog + get /server/traffic/list (FilterServerTrafficLogRequest) returns (FilterServerTrafficLogResponse) + + @doc "Filter balance log" + @handler FilterBalanceLog + get /balance/list (FilterBalanceLogRequest) returns (FilterBalanceLogResponse) + + @doc "Filter commission log" + @handler FilterCommissionLog + get /commission/list (FilterCommissionLogRequest) returns (FilterCommissionLogResponse) + + @doc "Filter gift log" + @handler FilterGiftLog + get /gift/list (FilterGiftLogRequest) returns (FilterGiftLogResponse) + + @doc "Filter traffic log details" + @handler FilterTrafficLogDetails + get /traffic/details (FilterTrafficLogDetailsRequest) returns (FilterTrafficLogDetailsResponse) + + @doc "Get log setting" + @handler GetLogSetting + get /setting returns (LogSetting) + + @doc "Update log setting" + @handler UpdateLogSetting + post /setting (LogSetting) } diff --git a/apis/admin/marketing.api b/apis/admin/marketing.api index 3f039ff..8014c0d 100644 --- a/apis/admin/marketing.api +++ b/apis/admin/marketing.api @@ -12,7 +12,7 @@ type ( CreateBatchSendEmailTaskRequest { Subject string `json:"subject"` Content string `json:"content"` - Scope string `json:"scope"` + Scope int8 `json:"scope"` RegisterStartTime int64 `json:"register_start_time,omitempty"` RegisterEndTime int64 `json:"register_end_time,omitempty"` Additional string `json:"additional,omitempty"` @@ -25,7 +25,7 @@ type ( Subject string `json:"subject"` Content string `json:"content"` Recipients string `json:"recipients"` - Scope string `json:"scope"` + Scope int8 `json:"scope"` RegisterStartTime int64 `json:"register_start_time"` RegisterEndTime int64 `json:"register_end_time"` Additional string `json:"additional"` @@ -42,7 +42,7 @@ type ( GetBatchSendEmailTaskListRequest { Page int `form:"page"` Size int `form:"size"` - Scope string `form:"scope,omitempty"` + Scope *int8 `form:"scope,omitempty"` Status *uint8 `form:"status,omitempty"` } GetBatchSendEmailTaskListResponse { @@ -53,9 +53,9 @@ type ( Id int64 `json:"id"` } GetPreSendEmailCountRequest { - Scope string `json:"scope"` - RegisterStartTime int64 `json:"register_start_time,omitempty"` - RegisterEndTime int64 `json:"register_end_time,omitempty"` + Scope int8 `json:"scope"` + RegisterStartTime int64 `json:"register_start_time,omitempty"` + RegisterEndTime int64 `json:"register_end_time,omitempty"` } GetPreSendEmailCountResponse { Count int64 `json:"count"` @@ -69,6 +69,61 @@ type ( Total int64 `json:"total"` Errors string `json:"errors"` } + CreateQuotaTaskRequest { + Subscribers []int64 `json:"subscribers"` + IsActive *bool `json:"is_active"` + StartTime int64 `json:"start_time"` + EndTime int64 `json:"end_time"` + ResetTraffic bool `json:"reset_traffic"` + Days uint64 `json:"days"` + GiftType uint8 `json:"gift_type"` + GiftValue uint64 `json:"gift_value"` + } + QuotaTask { + Id int64 `json:"id"` + Subscribers []int64 `json:"subscribers"` + IsActive *bool `json:"is_active"` + StartTime int64 `json:"start_time"` + EndTime int64 `json:"end_time"` + ResetTraffic bool `json:"reset_traffic"` + Days uint64 `json:"days"` + GiftType uint8 `json:"gift_type"` + GiftValue uint64 `json:"gift_value"` + Objects []int64 `json:"objects"` // UserSubscribe IDs + Status uint8 `json:"status"` + Total int64 `json:"total"` + Current int64 `json:"current"` + Errors string `json:"errors"` + CreatedAt int64 `json:"created_at"` + UpdatedAt int64 `json:"updated_at"` + } + QueryQuotaTaskPreCountRequest { + Subscribers []int64 `json:"subscribers"` + IsActive *bool `json:"is_active"` + StartTime int64 `json:"start_time"` + EndTime int64 `json:"end_time"` + } + QueryQuotaTaskPreCountResponse { + Count int64 `json:"count"` + } + QueryQuotaTaskListRequest { + Page int `form:"page"` + Size int `form:"size"` + Status *uint8 `form:"status,omitempty"` + } + QueryQuotaTaskListResponse { + Total int64 `json:"total"` + List []QuotaTask `json:"list"` + } + QueryQuotaTaskStatusRequest { + Id int64 `json:"id"` + } + QueryQuotaTaskStatusResponse { + Status uint8 `json:"status"` + Current int64 `json:"current"` + Total int64 `json:"total"` + Errors string `json:"errors"` + } ) @server ( @@ -96,5 +151,17 @@ service ppanel { @doc "Get batch send email task status" @handler GetBatchSendEmailTaskStatus post /email/batch/status (GetBatchSendEmailTaskStatusRequest) returns (GetBatchSendEmailTaskStatusResponse) + + @doc "Create a quota task" + @handler CreateQuotaTask + post /quota/create (CreateQuotaTaskRequest) + + @doc "Query quota task pre-count" + @handler QueryQuotaTaskPreCount + post /quota/pre-count (QueryQuotaTaskPreCountRequest) returns (QueryQuotaTaskPreCountResponse) + + @doc "Query quota task list" + @handler QueryQuotaTaskList + get /quota/list (QueryQuotaTaskListRequest) returns (QueryQuotaTaskListResponse) } diff --git a/apis/admin/server.api b/apis/admin/server.api index 2622278..cd73404 100644 --- a/apis/admin/server.api +++ b/apis/admin/server.api @@ -11,108 +11,137 @@ info ( import "../types.api" type ( - GetNodeServerListRequest { - Page int `form:"page" validate:"required"` - Size int `form:"size" validate:"required"` - Tags string `form:"tags,omitempty"` - GroupId int64 `form:"group_id,omitempty"` - Search string `form:"search,omitempty"` + ServerOnlineIP { + IP string `json:"ip"` + Protocol string `json:"protocol"` } - GetNodeServerListResponse { + ServerOnlineUser { + IP []ServerOnlineIP `json:"ip"` + UserId int64 `json:"user_id"` + Subscribe string `json:"subscribe"` + SubscribeId int64 `json:"subscribe_id"` + Traffic int64 `json:"traffic"` + ExpiredAt int64 `json:"expired_at"` + } + ServerStatus { + Cpu float64 `json:"cpu"` + Mem float64 `json:"mem"` + Disk float64 `json:"disk"` + Protocol string `json:"protocol"` + Online []ServerOnlineUser `json:"online"` + Status string `json:"status"` + } + Server { + Id int64 `json:"id"` + Name string `json:"name"` + Country string `json:"country"` + City string `json:"city"` + Ratio float32 `json:"ratio"` + Address string `json:"address"` + Sort int `json:"sort"` + Protocols []Protocol `json:"protocols"` + LastReportedAt int64 `json:"last_reported_at"` + Status ServerStatus `json:"status"` + CreatedAt int64 `json:"created_at"` + UpdatedAt int64 `json:"updated_at"` + } + CreateServerRequest { + Name string `json:"name"` + Country string `json:"country,omitempty"` + City string `json:"city,omitempty"` + Ratio float32 `json:"ratio"` + Address string `json:"address"` + Sort int `json:"sort,omitempty"` + Protocols []Protocol `json:"protocols"` + } + UpdateServerRequest { + Id int64 `json:"id"` + Name string `json:"name"` + Country string `json:"country,omitempty"` + City string `json:"city,omitempty"` + Ratio float32 `json:"ratio"` + Address string `json:"address"` + Sort int `json:"sort,omitempty"` + Protocols []Protocol `json:"protocols"` + } + DeleteServerRequest { + Id int64 `json:"id"` + } + FilterServerListRequest { + Page int `form:"page"` + Size int `form:"size"` + Search string `form:"search,omitempty"` + } + FilterServerListResponse { Total int64 `json:"total"` List []Server `json:"list"` } - UpdateNodeRequest { - Id int64 `json:"id" validate:"required"` - Tags []string `json:"tags"` - Country string `json:"country"` - City string `json:"city"` - Name string `json:"name" validate:"required"` - ServerAddr string `json:"server_addr" validate:"required"` - RelayMode string `json:"relay_mode"` - RelayNode []NodeRelay `json:"relay_node"` - SpeedLimit int `json:"speed_limit"` - TrafficRatio float32 `json:"traffic_ratio"` - GroupId int64 `json:"group_id"` - Protocol string `json:"protocol" validate:"required"` - Config interface{} `json:"config" validate:"required"` - Enable *bool `json:"enable"` - Sort int64 `json:"sort"` + GetServerProtocolsRequest { + Id int64 `form:"id"` + } + GetServerProtocolsResponse { + Protocols []Protocol `json:"protocols"` + } + Node { + Id int64 `json:"id"` + Name string `json:"name"` + Tags []string `json:"tags"` + Port uint16 `json:"port"` + Address string `json:"address"` + ServerId int64 `json:"server_id"` + Protocol string `json:"protocol"` + Enabled *bool `json:"enabled"` + Sort int `json:"sort,omitempty"` + CreatedAt int64 `json:"created_at"` + UpdatedAt int64 `json:"updated_at"` } CreateNodeRequest { - Name string `json:"name" validate:"required"` - Tags []string `json:"tags"` - Country string `json:"country"` - City string `json:"city"` - ServerAddr string `json:"server_addr" validate:"required"` - RelayMode string `json:"relay_mode"` - RelayNode []NodeRelay `json:"relay_node"` - SpeedLimit int `json:"speed_limit"` - TrafficRatio float32 `json:"traffic_ratio"` - GroupId int64 `json:"group_id"` - Protocol string `json:"protocol" validate:"required"` - Config interface{} `json:"config" validate:"required"` - Enable *bool `json:"enable"` - Sort int64 `json:"sort"` + Name string `json:"name"` + Tags []string `json:"tags,omitempty"` + Port uint16 `json:"port"` + Address string `json:"address"` + ServerId int64 `json:"server_id"` + Protocol string `json:"protocol"` + Enabled *bool `json:"enabled"` + } + UpdateNodeRequest { + Id int64 `json:"id"` + Name string `json:"name"` + Tags []string `json:"tags,omitempty"` + Port uint16 `json:"port"` + Address string `json:"address"` + ServerId int64 `json:"server_id"` + Protocol string `json:"protocol"` + Enabled *bool `json:"enabled"` + } + ToggleNodeStatusRequest { + Id int64 `json:"id"` + Enable *bool `json:"enable"` } DeleteNodeRequest { - Id int64 `json:"id" validate:"required"` + Id int64 `json:"id"` } - GetNodeGroupListResponse { - Total int64 `json:"total"` - List []ServerGroup `json:"list"` + FilterNodeListRequest { + Page int `form:"page"` + Size int `form:"size"` + Search string `form:"search,omitempty"` } - CreateNodeGroupRequest { - Name string `json:"name" validate:"required"` - Description string `json:"description"` + FilterNodeListResponse { + Total int64 `json:"total"` + List []Node `json:"list"` } - UpdateNodeGroupRequest { - Id int64 `json:"id" validate:"required"` - Name string `json:"name" validate:"required"` - Description string `json:"description"` + HasMigrateSeverNodeResponse { + HasMigrate bool `json:"has_migrate"` } - DeleteNodeGroupRequest { - Id int64 `json:"id" validate:"required"` + MigrateServerNodeResponse { + Succee uint64 `json:"succee"` + Fail uint64 `json:"fail"` + Message string `json:"message,omitempty"` } - BatchDeleteNodeRequest { - Ids []int64 `json:"ids" validate:"required"` - } - BatchDeleteNodeGroupRequest { - Ids []int64 `json:"ids" validate:"required"` - } - GetNodeDetailRequest { - Id int64 `form:"id" validate:"required"` - } - NodeSortRequest { + ResetSortRequest { Sort []SortItem `json:"sort"` } - CreateRuleGroupRequest { - Name string `json:"name" validate:"required"` - Icon string `json:"icon"` - Type string `json:"type"` - Tags []string `json:"tags"` - Rules string `json:"rules"` - Default bool `json:"default"` - Enable bool `json:"enable"` - } - UpdateRuleGroupRequest { - Id int64 `json:"id" validate:"required"` - Icon string `json:"icon"` - Type string `json:"type"` - Name string `json:"name" validate:"required"` - Tags []string `json:"tags"` - Rules string `json:"rules"` - Default bool `json:"default"` - Enable bool `json:"enable"` - } - DeleteRuleGroupRequest { - Id int64 `json:"id" validate:"required"` - } - GetRuleGroupResponse { - Total int64 `json:"total"` - List []ServerRuleGroup `json:"list"` - } - GetNodeTagListResponse { + QueryNodeTagResponse { Tags []string `json:"tags"` } ) @@ -123,72 +152,64 @@ type ( middleware: AuthMiddleware ) service ppanel { - @doc "Get node tag list" - @handler GetNodeTagList - get /tag/list returns (GetNodeTagListResponse) + @doc "Create Server" + @handler CreateServer + post /create (CreateServerRequest) - @doc "Get node list" - @handler GetNodeList - get /list (GetNodeServerListRequest) returns (GetNodeServerListResponse) + @doc "Update Server" + @handler UpdateServer + post /update (UpdateServerRequest) - @doc "Get node detail" - @handler GetNodeDetail - get /detail (GetNodeDetailRequest) returns (Server) + @doc "Delete Server" + @handler DeleteServer + post /delete (DeleteServerRequest) - @doc "Update node" - @handler UpdateNode - put / (UpdateNodeRequest) + @doc "Filter Server List" + @handler FilterServerList + get /list (FilterServerListRequest) returns (FilterServerListResponse) - @doc "Create node" + @doc "Get Server Protocols" + @handler GetServerProtocols + get /protocols (GetServerProtocolsRequest) returns (GetServerProtocolsResponse) + + @doc "Create Node" @handler CreateNode - post / (CreateNodeRequest) + post /node/create (CreateNodeRequest) - @doc "Delete node" + @doc "Update Node" + @handler UpdateNode + post /node/update (UpdateNodeRequest) + + @doc "Delete Node" @handler DeleteNode - delete / (DeleteNodeRequest) + post /node/delete (DeleteNodeRequest) - @doc "Batch delete node" - @handler BatchDeleteNode - delete /batch (BatchDeleteNodeRequest) + @doc "Filter Node List" + @handler FilterNodeList + get /node/list (FilterNodeListRequest) returns (FilterNodeListResponse) - @doc "Get node group list" - @handler GetNodeGroupList - get /group/list returns (GetNodeGroupListResponse) + @doc "Toggle Node Status" + @handler ToggleNodeStatus + post /node/status/toggle (ToggleNodeStatusRequest) - @doc "Create node group" - @handler CreateNodeGroup - post /group (CreateNodeGroupRequest) + @doc "Check if there is any server or node to migrate" + @handler HasMigrateSeverNode + get /migrate/has returns (HasMigrateSeverNodeResponse) - @doc "Update node group" - @handler UpdateNodeGroup - put /group (UpdateNodeGroupRequest) + @doc "Migrate server and node data to new database" + @handler MigrateServerNode + post /migrate/run returns (MigrateServerNodeResponse) - @doc "Delete node group" - @handler DeleteNodeGroup - delete /group (DeleteNodeGroupRequest) + @doc "Reset server sort" + @handler ResetSortWithServer + post /server/sort (ResetSortRequest) - @doc "Batch delete node group" - @handler BatchDeleteNodeGroup - delete /group/batch (BatchDeleteNodeGroupRequest) + @doc "Reset node sort" + @handler ResetSortWithNode + post /node/sort (ResetSortRequest) - @doc "Node sort " - @handler NodeSort - post /sort (NodeSortRequest) - - @doc "Create rule group" - @handler CreateRuleGroup - post /rule_group (CreateRuleGroupRequest) - - @doc "Update rule group" - @handler UpdateRuleGroup - put /rule_group (UpdateRuleGroupRequest) - - @doc "Delete rule group" - @handler DeleteRuleGroup - delete /rule_group (DeleteRuleGroupRequest) - - @doc "Get rule group list" - @handler GetRuleGroupList - get /rule_group_list returns (GetRuleGroupResponse) + @doc "Query all node tags" + @handler QueryNodeTag + get /node/tags returns (QueryNodeTagResponse) } diff --git a/apis/admin/subscribe.api b/apis/admin/subscribe.api index 4e79c03..1d08b65 100644 --- a/apis/admin/subscribe.api +++ b/apis/admin/subscribe.api @@ -35,6 +35,7 @@ type ( } CreateSubscribeRequest { Name string `json:"name" validate:"required"` + Language string `json:"language"` Description string `json:"description"` UnitPrice int64 `json:"unit_price"` UnitTime string `json:"unit_time"` @@ -45,9 +46,8 @@ type ( SpeedLimit int64 `json:"speed_limit"` DeviceLimit int64 `json:"device_limit"` Quota int64 `json:"quota"` - GroupId int64 `json:"group_id"` - ServerGroup []int64 `json:"server_group"` - Server []int64 `json:"server"` + Nodes []int64 `json:"nodes"` + NodeTags []string `json:"node_tags"` Show *bool `json:"show"` Sell *bool `json:"sell"` DeductionRatio int64 `json:"deduction_ratio"` @@ -58,6 +58,7 @@ type ( UpdateSubscribeRequest { Id int64 `json:"id" validate:"required"` Name string `json:"name" validate:"required"` + Language string `json:"language"` Description string `json:"description"` UnitPrice int64 `json:"unit_price"` UnitTime string `json:"unit_time"` @@ -68,9 +69,8 @@ type ( SpeedLimit int64 `json:"speed_limit"` DeviceLimit int64 `json:"device_limit"` Quota int64 `json:"quota"` - GroupId int64 `json:"group_id"` - ServerGroup []int64 `json:"server_group"` - Server []int64 `json:"server"` + Nodes []int64 `json:"nodes"` + NodeTags []string `json:"node_tags"` Show *bool `json:"show"` Sell *bool `json:"sell"` Sort int64 `json:"sort"` @@ -83,10 +83,10 @@ type ( Sort []SortItem `json:"sort"` } GetSubscribeListRequest { - Page int64 `form:"page" validate:"required"` - Size int64 `form:"size" validate:"required"` - GroupId int64 `form:"group_id,omitempty"` - Search string `form:"search,omitempty"` + Page int64 `form:"page" validate:"required"` + Size int64 `form:"size" validate:"required"` + Language string `form:"language,omitempty"` + Search string `form:"search,omitempty"` } SubscribeItem { Subscribe diff --git a/apis/admin/system.api b/apis/admin/system.api index 09323c3..21d2c73 100644 --- a/apis/admin/system.api +++ b/apis/admin/system.api @@ -11,50 +11,6 @@ info ( import "../types.api" type ( - // Update application request - UpdateApplicationRequest { - Id int64 `json:"id" validate:"required"` - Icon string `json:"icon"` - Name string `json:"name"` - Description string `json:"description"` - SubscribeType string `json:"subscribe_type"` - Platform ApplicationPlatform `json:"platform"` - } - // Create application request - CreateApplicationRequest { - Icon string `json:"icon"` - Name string `json:"name"` - Description string `json:"description"` - SubscribeType string `json:"subscribe_type"` - Platform ApplicationPlatform `json:"platform"` - } - // Update application request - UpdateApplicationVersionRequest { - Id int64 `json:"id" validate:"required"` - Url string `json:"url"` - Version string `json:"version" validate:"required"` - Description string `json:"description"` - Platform string `json:"platform" validate:"required,oneof=windows mac linux android ios harmony"` - IsDefault bool `json:"is_default"` - ApplicationId int64 `json:"application_id" validate:"required"` - } - // Create application request - CreateApplicationVersionRequest { - Url string `json:"url"` - Version string `json:"version" validate:"required"` - Description string `json:"description"` - Platform string `json:"platform" validate:"required,oneof=windows mac linux android ios harmony"` - IsDefault bool `json:"is_default"` - ApplicationId int64 `json:"application_id" validate:"required"` - } - // Delete application request - DeleteApplicationRequest { - Id int64 `json:"id" validate:"required"` - } - // Delete application request - DeleteApplicationVersionRequest { - Id int64 `json:"id" validate:"required"` - } GetNodeMultiplierResponse { Periods []TimePeriod `json:"periods"` } @@ -86,46 +42,6 @@ service ppanel { @handler UpdateSubscribeConfig put /subscribe_config (SubscribeConfig) - @doc "Get subscribe type" - @handler GetSubscribeType - get /subscribe_type returns (SubscribeType) - - @doc "update application config" - @handler UpdateApplicationConfig - put /application_config (ApplicationConfig) - - @doc "get application config" - @handler GetApplicationConfig - get /application_config returns (ApplicationConfig) - - @doc "Get application" - @handler GetApplication - get /application returns (ApplicationResponse) - - @doc "Update application" - @handler UpdateApplication - put /application (UpdateApplicationRequest) - - @doc "Create application" - @handler CreateApplication - post /application (CreateApplicationRequest) - - @doc "Delete application" - @handler DeleteApplication - delete /application (DeleteApplicationRequest) - - @doc "Update application version" - @handler UpdateApplicationVersion - put /application_version (UpdateApplicationVersionRequest) - - @doc "Create application version" - @handler CreateApplicationVersion - post /application_version (CreateApplicationVersionRequest) - - @doc "Delete application" - @handler DeleteApplicationVersion - delete /application_version (DeleteApplicationVersionRequest) - @doc "Get register config" @handler GetRegisterConfig get /register_config returns (RegisterConfig) diff --git a/apis/admin/user.api b/apis/admin/user.api index 92149fd..dc0c5e8 100644 --- a/apis/admin/user.api +++ b/apis/admin/user.api @@ -32,17 +32,19 @@ type ( Id int64 `form:"id" validate:"required"` } UpdateUserBasiceInfoRequest { - UserId int64 `json:"user_id" validate:"required"` - Password string `json:"password"` - Avatar string `json:"avatar"` - Balance int64 `json:"balance"` - Commission int64 `json:"commission"` - GiftAmount int64 `json:"gift_amount"` - Telegram int64 `json:"telegram"` - ReferCode string `json:"refer_code"` - RefererId int64 `json:"referer_id"` - Enable bool `json:"enable"` - IsAdmin bool `json:"is_admin"` + UserId int64 `json:"user_id" validate:"required"` + Password string `json:"password"` + Avatar string `json:"avatar"` + Balance int64 `json:"balance"` + Commission int64 `json:"commission"` + ReferralPercentage uint8 `json:"referral_percentage"` + OnlyFirstPurchase bool `json:"only_first_purchase"` + GiftAmount int64 `json:"gift_amount"` + Telegram int64 `json:"telegram"` + ReferCode string `json:"refer_code"` + RefererId int64 `json:"referer_id"` + Enable bool `json:"enable"` + IsAdmin bool `json:"is_admin"` } UpdateUserNotifySettingRequest { UserId int64 `json:"user_id" validate:"required"` @@ -52,18 +54,20 @@ type ( EnableTradeNotify bool `json:"enable_trade_notify"` } CreateUserRequest { - Email string `json:"email"` - Telephone string `json:"telephone"` - TelephoneAreaCode string `json:"telephone_area_code"` - Password string `json:"password"` - ProductId int64 `json:"product_id"` - Duration int64 `json:"duration"` - RefererUser string `json:"referer_user"` - ReferCode string `json:"refer_code"` - Balance int64 `json:"balance"` - Commission int64 `json:"commission"` - GiftAmount int64 `json:"gift_amount"` - IsAdmin bool `json:"is_admin"` + Email string `json:"email"` + Telephone string `json:"telephone"` + TelephoneAreaCode string `json:"telephone_area_code"` + Password string `json:"password"` + ProductId int64 `json:"product_id"` + Duration int64 `json:"duration"` + ReferralPercentage uint8 `json:"referral_percentage"` + OnlyFirstPurchase bool `json:"only_first_purchase"` + RefererUser string `json:"referer_user"` + ReferCode string `json:"refer_code"` + Balance int64 `json:"balance"` + Commission int64 `json:"commission"` + GiftAmount int64 `json:"gift_amount"` + IsAdmin bool `json:"is_admin"` } UserSubscribeDetail { Id int64 `json:"id"` @@ -164,6 +168,15 @@ type ( List []UserLoginLog `json:"list"` Total int64 `json:"total"` } + GetUserSubscribeResetTrafficLogsRequest { + Page int `form:"page"` + Size int `form:"size"` + UserSubscribeId int64 `form:"user_subscribe_id"` + } + GetUserSubscribeResetTrafficLogsResponse { + List []ResetSubscribeTrafficLog `json:"list"` + Total int64 `json:"total"` + } DeleteUserSubscribeRequest { UserSubscribeId int64 `json:"user_subscribe_id"` } @@ -251,6 +264,10 @@ service ppanel { @handler GetUserSubscribeLogs get /subscribe/logs (GetUserSubscribeLogsRequest) returns (GetUserSubscribeLogsResponse) + @doc "Get user subcribe reset traffic logs" + @handler GetUserSubscribeResetTrafficLogs + get /subscribe/reset/logs (GetUserSubscribeResetTrafficLogsRequest) returns (GetUserSubscribeResetTrafficLogsResponse) + @doc "Get user subcribe traffic logs" @handler GetUserSubscribeTrafficLogs get /subscribe/traffic_logs (GetUserSubscribeTrafficLogsRequest) returns (GetUserSubscribeTrafficLogsResponse) diff --git a/apis/app/announcement.api b/apis/app/announcement.api deleted file mode 100644 index 52209ed..0000000 --- a/apis/app/announcement.api +++ /dev/null @@ -1,23 +0,0 @@ -syntax = "v1" - -info ( - title: "Announcement API" - desc: "API for ppanel" - author: "Tension" - email: "tension@ppanel.com" - version: "0.0.1" -) - -import "../types.api" - -@server ( - prefix: v1/app/announcement - group: app/announcement - middleware: AppMiddleware,AuthMiddleware -) -service ppanel { - @doc "Query announcement" - @handler QueryAnnouncement - get /list (QueryAnnouncementRequest) returns (QueryAnnouncementResponse) -} - diff --git a/apis/app/auth.api b/apis/app/auth.api deleted file mode 100644 index 779e09e..0000000 --- a/apis/app/auth.api +++ /dev/null @@ -1,104 +0,0 @@ -syntax = "v1" - -info ( - title: "App Auth Api" - desc: "API for ppanel" - author: "Tension" - email: "tension@ppanel.com" - version: "0.0.1" -) - -import ( - "../types.api" -) - -type ( - AppAuthCheckRequest { - Method string `json:"method" validate:"required" validate:"required,oneof=device email mobile"` - Account string `json:"account"` - Identifier string `json:"identifier" validate:"required"` - UserAgent string `json:"user_agent" validate:"required,oneof=windows mac linux android ios harmony"` - AreaCode string `json:"area_code"` - } - AppAuthCheckResponse { - Status bool - } - AppAuthRequest { - Method string `json:"method" validate:"required" validate:"required,oneof=device email mobile"` - Account string `json:"account"` - Password string `json:"password"` - Identifier string `json:"identifier" validate:"required"` - UserAgent string `json:"user_agent" validate:"required,oneof=windows mac linux android ios harmony"` - Code string `json:"code"` - Invite string `json:"invite"` - AreaCode string `json:"area_code"` - CfToken string `json:"cf_token,optional"` - } - AppAuthRespone { - Token string `json:"token"` - } - AppSendCodeRequest { - Method string `json:"method" validate:"required" validate:"required,oneof=email mobile"` - Account string `json:"account"` - AreaCode string `json:"area_code"` - CfToken string `json:"cf_token,optional"` - } - AppSendCodeRespone { - Status bool `json:"status"` - Code string `json:"code,omitempty"` - } - AppConfigRequest { - UserAgent string `json:"user_agent" validate:"required,oneof=windows mac linux android ios harmony"` - } - AppConfigResponse { - EncryptionKey string `json:"encryption_key"` - EncryptionMethod string `json:"encryption_method"` - Domains []string `json:"domains"` - StartupPicture string `json:"startup_picture"` - StartupPictureSkipTime int64 `json:"startup_picture_skip_time"` - Application AppInfo `json:"applications"` - OfficialEmail string `json:"official_email"` - OfficialWebsite string `json:"official_website"` - OfficialTelegram string `json:"official_telegram"` - OfficialTelephone string `json:"official_telephone"` - InvitationLink string `json:"invitation_link"` - KrWebsiteId string `json:"kr_website_id"` - } - AppInfo { - Id int64 `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - Url string `json:"url"` - Version string `json:"version"` - VersionDescription string `json:"version_description"` - IsDefault bool `json:"is_default"` - } -) - -@server ( - prefix: v1/app/auth - group: app/auth - middleware: AppMiddleware -) -service ppanel { - @doc "Check Account" - @handler Check - post /check (AppAuthCheckRequest) returns (AppAuthCheckResponse) - - @doc "Login" - @handler Login - post /login (AppAuthRequest) returns (AppAuthRespone) - - @doc "Register" - @handler Register - post /register (AppAuthRequest) returns (AppAuthRespone) - - @doc "Reset Password" - @handler ResetPassword - post /reset_password (AppAuthRequest) returns (AppAuthRespone) - - @doc "GetAppConfig" - @handler GetAppConfig - post /config (AppConfigRequest) returns (AppConfigResponse) -} - diff --git a/apis/app/document.api b/apis/app/document.api deleted file mode 100644 index 5dfaec0..0000000 --- a/apis/app/document.api +++ /dev/null @@ -1,27 +0,0 @@ -syntax = "v1" - -info ( - title: "Document API" - desc: "API for ppanel" - author: "Tension" - email: "tension@ppanel.com" - version: "0.0.1" -) - -import "../types.api" - -@server ( - prefix: v1/app/document - group: app/document - middleware: AppMiddleware,AuthMiddleware -) -service ppanel { - @doc "Get document list" - @handler QueryDocumentList - get /list returns (QueryDocumentListResponse) - - @doc "Get document detail" - @handler QueryDocumentDetail - get /detail (QueryDocumentDetailRequest) returns (Document) -} - diff --git a/apis/app/node.api b/apis/app/node.api deleted file mode 100644 index df3232b..0000000 --- a/apis/app/node.api +++ /dev/null @@ -1,40 +0,0 @@ -syntax = "v1" - -info ( - title: "App Node Api" - desc: "API for ppanel" - author: "Tension" - email: "tension@ppanel.com" - version: "0.0.1" -) - -import "../types.api" - -type ( - AppRuleGroupListResponse { - Total int64 `json:"total"` - List []ServerRuleGroup `json:"list"` - } - AppUserSubscbribeNodeRequest { - Id int64 `form:"id" validate:"required"` - } - AppUserSubscbribeNodeResponse { - List []AppUserSubscbribeNode `json:"list"` - } -) - -@server ( - prefix: v1/app/node - group: app/node - middleware: AppMiddleware,AuthMiddleware -) -service ppanel { - @doc "Get Node list" - @handler GetNodeList - get /list (AppUserSubscbribeNodeRequest) returns (AppUserSubscbribeNodeResponse) - - @doc "Get rule group list" - @handler GetRuleGroupList - get /rule_group_list returns (AppRuleGroupListResponse) -} - diff --git a/apis/app/order.api b/apis/app/order.api deleted file mode 100644 index 301d62b..0000000 --- a/apis/app/order.api +++ /dev/null @@ -1,57 +0,0 @@ -syntax = "v1" - -info ( - title: "Order API" - desc: "API for ppanel" - author: "Tension" - email: "tension@ppanel.com" - version: "0.0.1" -) - -import ( - "../types.api" -) - -@server ( - prefix: v1/app/order - group: app/order - middleware: AppMiddleware,AuthMiddleware -) -service ppanel { - @doc "Pre create order" - @handler PreCreateOrder - post /pre (PurchaseOrderRequest) returns (PreOrderResponse) - - @doc "purchase Subscription" - @handler Purchase - post /purchase (PurchaseOrderRequest) returns (PurchaseOrderResponse) - - @doc "Renewal Subscription" - @handler Renewal - post /renewal (RenewalOrderRequest) returns (RenewalOrderResponse) - - @doc "Reset traffic" - @handler ResetTraffic - post /reset (ResetTrafficOrderRequest) returns (ResetTrafficOrderResponse) - - @doc "Recharge" - @handler Recharge - post /recharge (RechargeOrderRequest) returns (RechargeOrderResponse) - - @doc "Checkout order" - @handler CheckoutOrder - post /checkout (CheckoutOrderRequest) returns (CheckoutOrderResponse) - - @doc "Close order" - @handler CloseOrder - post /close (CloseOrderRequest) - - @doc "Get order" - @handler QueryOrderDetail - get /detail (QueryOrderDetailRequest) returns (OrderDetail) - - @doc "Get order list" - @handler QueryOrderList - get /list (QueryOrderListRequest) returns (QueryOrderListResponse) -} - diff --git a/apis/app/payment.api b/apis/app/payment.api deleted file mode 100644 index 9769a47..0000000 --- a/apis/app/payment.api +++ /dev/null @@ -1,23 +0,0 @@ -syntax = "v1" - -info ( - title: "payment API" - desc: "API for ppanel" - author: "Tension" - email: "tension@ppanel.com" - version: "0.0.1" -) - -import "../types.api" - -@server ( - prefix: v1/app/payment - group: app/payment - middleware: AppMiddleware,AuthMiddleware -) -service ppanel { - @doc "Get available payment methods" - @handler GetAvailablePaymentMethods - get /methods returns (GetAvailablePaymentMethodsResponse) -} - diff --git a/apis/app/subscribe.api b/apis/app/subscribe.api deleted file mode 100644 index 8ee9665..0000000 --- a/apis/app/subscribe.api +++ /dev/null @@ -1,65 +0,0 @@ -syntax = "v1" - -info ( - title: "Subscribe API" - desc: "API for ppanel" - author: "Tension" - email: "tension@ppanel.com" - version: "0.0.1" -) - -import "../types.api" - -type ( - QueryUserSubscribeResp { - Data []UserSubscribeData `json:"data"` - } - UserSubscribeData { - SubscribeId int64 `json:"subscribe_id"` - UserSubscribeId int64 `json:"user_subscribe_id"` - } - UserSubscribeResetPeriodRequest { - UserSubscribeId int64 `json:"user_subscribe_id"` - } - UserSubscribeResetPeriodResponse { - Status bool `json:"status"` - } - AppUserSubscribeRequest { - ContainsNodes *bool `form:"contains_nodes"` - } - AppUserSubscbribeResponse { - List []AppUserSubcbribe `json:"list"` - } -) - -@server ( - prefix: v1/app/subscribe - group: app/subscribe - middleware: AppMiddleware,AuthMiddleware -) -service ppanel { - @doc "Get subscribe list" - @handler QuerySubscribeList - get /list returns (QuerySubscribeListResponse) - - @doc "Get subscribe group list" - @handler QuerySubscribeGroupList - get /group/list returns (QuerySubscribeGroupListResponse) - - @doc "Get application config" - @handler QueryApplicationConfig - get /application/config returns (ApplicationResponse) - - @doc "Get Already subscribed to package" - @handler QueryUserAlreadySubscribe - get /user/already_subscribe returns (QueryUserSubscribeResp) - - @doc "Get Available subscriptions for users" - @handler QueryUserAvailableUserSubscribe - get /user/available_subscribe (AppUserSubscribeRequest) returns (AppUserSubscbribeResponse) - - @doc "Reset user subscription period" - @handler ResetUserSubscribePeriod - post /reset/period (UserSubscribeResetPeriodRequest) returns (UserSubscribeResetPeriodResponse) -} - diff --git a/apis/app/user.api b/apis/app/user.api deleted file mode 100644 index 953974a..0000000 --- a/apis/app/user.api +++ /dev/null @@ -1,86 +0,0 @@ -syntax = "v1" - -info ( - title: "App User Api" - desc: "API for ppanel" - author: "Tension" - email: "tension@ppanel.com" - version: "0.0.1" -) - -import ( - "../types.api" -) - -type ( - UserInfoResponse { - Id int64 `json:"id"` - Balance int64 `json:"balance"` - Email string `json:"email"` - RefererId int64 `json:"referer_id"` - ReferCode string `json:"refer_code"` - Avatar string `json:"avatar"` - AreaCode string `json:"area_code"` - Telephone string `json:"telephone"` - Devices []UserDevice `json:"devices"` - AuthMethods []UserAuthMethod `json:"auth_methods"` - } - UpdatePasswordRequeset { - Password string `json:"password"` - NewPassword string `json:"new_password"` - } - DeleteAccountRequest { - Method string `json:"method" validate:"required" validate:"required,oneof=email telephone device"` - Code string `json:"code"` - } - GetUserOnlineTimeStatisticsResponse { - WeeklyStats []WeeklyStat `json:"weekly_stats"` - ConnectionRecords ConnectionRecords `json:"connection_records"` - } - WeeklyStat { - Day int `json:"day"` - DayName string `json:"day_name"` - Hours float64 `json:"hours"` - } - ConnectionRecords { - CurrentContinuousDays int64 `json:"current_continuous_days"` - HistoryContinuousDays int64 `json:"history_continuous_days"` - LongestSingleConnection int64 `json:"longest_single_connection"` - } -) - -@server ( - prefix: v1/app/user - group: app/user - middleware: AppMiddleware,AuthMiddleware -) -service ppanel { - @doc "query user info" - @handler QueryUserInfo - get /info returns (UserInfoResponse) - - @doc "Update Password " - @handler UpdatePassword - put /password (UpdatePasswordRequeset) - - @doc "Delete Account" - @handler DeleteAccount - delete /account (DeleteAccountRequest) - - @doc "Get user subcribe traffic logs" - @handler GetUserSubscribeTrafficLogs - get /subscribe/traffic_logs (GetUserSubscribeTrafficLogsRequest) returns (GetUserSubscribeTrafficLogsResponse) - - @doc "Get user online time total" - @handler GetUserOnlineTimeStatistics - get /online_time/statistics returns (GetUserOnlineTimeStatisticsResponse) - - @doc "Query User Affiliate List" - @handler QueryUserAffiliateList - get /affiliate/list (QueryUserAffiliateListRequest) returns (QueryUserAffiliateListResponse) - - @doc "Query User Affiliate Count" - @handler QueryUserAffiliate - get /affiliate/count returns (QueryUserAffiliateCountResponse) -} - diff --git a/apis/app/ws.api b/apis/app/ws.api deleted file mode 100644 index f70b55e..0000000 --- a/apis/app/ws.api +++ /dev/null @@ -1,21 +0,0 @@ -syntax = "v1" - -info ( - title: "App Heartbeat Api" - desc: "API for ppanel" - author: "Tension" - email: "tension@ppanel.com" - version: "0.0.1" -) - -@server ( - prefix: v1/app/ws - group: app/ws - middleware: AuthMiddleware -) -service ppanel { - @doc "App heartbeat" - @handler AppWs - get /:userid/:identifier -} - diff --git a/apis/auth/auth.api b/apis/auth/auth.api index 50c82d1..cb7225d 100644 --- a/apis/auth/auth.api +++ b/apis/auth/auth.api @@ -65,6 +65,7 @@ type ( TelephoneAreaCode string `json:"telephone_area_code" validate:"required"` Password string `json:"password"` IP string `header:"X-Original-Forwarded-For"` + UserAgent string `header:"User-Agent"` CfToken string `json:"cf_token,optional"` } // Check user is exist request @@ -84,6 +85,7 @@ type ( Invite string `json:"invite,optional"` Code string `json:"code,optional"` IP string `header:"X-Original-Forwarded-For"` + UserAgent string `header:"User-Agent"` CfToken string `json:"cf_token,optional"` } // User login response @@ -93,6 +95,7 @@ type ( Password string `json:"password" validate:"required"` Code string `json:"code,optional"` IP string `header:"X-Original-Forwarded-For"` + UserAgent string `header:"User-Agent"` CfToken string `json:"cf_token,optional"` } AppleLoginCallbackRequest { diff --git a/apis/common.api b/apis/common.api index 1b1c38e..6617a17 100644 --- a/apis/common.api +++ b/apis/common.api @@ -35,10 +35,6 @@ type ( GetTosResponse { TosContent string `json:"tos_content"` } - GetAppcationResponse { - Config ApplicationConfig `json:"config"` - Applications []ApplicationResponseInfo `json:"applications"` - } // GetCodeRequest Get code request SendCodeRequest { Email string `json:"email" validate:"required"` @@ -102,10 +98,6 @@ service ppanel { @handler GetGlobalConfig get /site/config returns (GetGlobalConfigResponse) - @doc "Get Tos Content" - @handler GetApplication - get /application returns (GetAppcationResponse) - @doc "Get Tos Content" @handler GetTos get /site/tos returns (GetTosResponse) diff --git a/apis/node/node.api b/apis/node/node.api index 156bf64..2952162 100644 --- a/apis/node/node.api +++ b/apis/node/node.api @@ -11,6 +11,10 @@ info ( import "../types.api" type ( + OnlineUser { + SID int64 `json:"uid"` + IP string `json:"ip"` + } ShadowsocksProtocol { Port int `json:"port"` Method string `json:"method"` @@ -89,6 +93,13 @@ type ( ServerCommon Users []OnlineUser `json:"users"` } + QueryServerConfigRequest { + ServerID int64 `path:"server_id"` + SecretKey string `header:"secret_key"` + } + QueryServerConfigResponse { + Protocols []Protocol `json:"protocols"` + } ) @server ( @@ -118,3 +129,13 @@ service ppanel { post /online (OnlineUsersRequest) } +@server ( + prefix: v2/server + group: server +) +service ppanel { + @doc "Get Server Protocol Config" + @handler QueryServerProtocolConfig + get /:server_id (QueryServerConfigRequest) returns (QueryServerConfigResponse) +} + diff --git a/apis/public/portal.api b/apis/public/portal.api index e900ed9..33d9948 100644 --- a/apis/public/portal.api +++ b/apis/public/portal.api @@ -25,6 +25,9 @@ type ( PortalPurchaseResponse { OrderNo string `json:"order_no"` } + GetSubscriptionRequest { + Language string `form:"language"` + } GetSubscriptionResponse { List []Subscribe `json:"list"` } @@ -75,7 +78,7 @@ service ppanel { @doc "Get Subscription" @handler GetSubscription - get /subscribe returns (GetSubscriptionResponse) + get /subscribe (GetSubscriptionRequest) returns (GetSubscriptionResponse) @doc "Pre Purchase Order" @handler PrePurchaseOrder diff --git a/apis/public/subscribe.api b/apis/public/subscribe.api index aaffe59..c5eaa63 100644 --- a/apis/public/subscribe.api +++ b/apis/public/subscribe.api @@ -10,6 +10,12 @@ info ( import "../types.api" +type ( + QuerySubscribeListRequest { + Language string `form:"language"` + } +) + @server ( prefix: v1/public/subscribe group: public/subscribe @@ -18,14 +24,6 @@ import "../types.api" service ppanel { @doc "Get subscribe list" @handler QuerySubscribeList - get /list returns (QuerySubscribeListResponse) - - @doc "Get subscribe group list" - @handler QuerySubscribeGroupList - get /group/list returns (QuerySubscribeGroupListResponse) - - @doc "Get application config" - @handler QueryApplicationConfig - get /application/config returns (ApplicationResponse) + get /list (QuerySubscribeListRequest) returns (QuerySubscribeListResponse) } diff --git a/apis/public/user.api b/apis/public/user.api index 66c8d08..3236bc5 100644 --- a/apis/public/user.api +++ b/apis/public/user.api @@ -25,15 +25,8 @@ type ( Total int64 `json:"total"` } QueryUserBalanceLogListResponse { - List []UserBalanceLog `json:"list"` - Total int64 `json:"total"` - } - CommissionLog { - Id int64 `json:"id"` - UserId int64 `json:"user_id"` - OrderNo string `json:"order_no"` - Amount int64 `json:"amount"` - CreatedAt int64 `json:"created_at"` + List []BalanceLog `json:"list"` + Total int64 `json:"total"` } QueryUserCommissionLogListRequest { Page int `form:"page"` diff --git a/apis/swagger_app.api b/apis/swagger_app.api deleted file mode 100644 index 590b5bf..0000000 --- a/apis/swagger_app.api +++ /dev/null @@ -1,22 +0,0 @@ -syntax = "v1" - -info ( - title: "App API" - desc: "API for ppanel" - author: "Tension" - email: "tension@ppanel.com" - version: "0.0.1" -) - -import ( - "./app/auth.api" - "./app/user.api" - "./app/node.api" - "./app/ws.api" - "./app/order.api" - "./app/announcement.api" - "./app/payment.api" - "./app/document.api" - "./app/subscribe.api" -) - diff --git a/apis/types.api b/apis/types.api index 13944e7..8f5f2d2 100644 --- a/apis/types.api +++ b/apis/types.api @@ -14,6 +14,8 @@ type ( Avatar string `json:"avatar"` Balance int64 `json:"balance"` Commission int64 `json:"commission"` + ReferralPercentage uint8 `json:"referral_percentage"` + OnlyFirstPurchase bool `json:"only_first_purchase"` GiftAmount int64 `json:"gift_amount"` Telegram int64 `json:"telegram"` ReferCode string `json:"refer_code"` @@ -183,6 +185,7 @@ type ( Subscribe { Id int64 `json:"id"` Name string `json:"name"` + Language string `json:"language"` Description string `json:"description"` UnitPrice int64 `json:"unit_price"` UnitTime string `json:"unit_time"` @@ -193,9 +196,8 @@ type ( SpeedLimit int64 `json:"speed_limit"` DeviceLimit int64 `json:"device_limit"` Quota int64 `json:"quota"` - GroupId int64 `json:"group_id"` - ServerGroup []int64 `json:"server_group"` - Server []int64 `json:"server"` + Nodes []int64 `json:"nodes"` + NodeTags []string `json:"node_tags"` Show bool `json:"show"` Sell bool `json:"sell"` Sort int64 `json:"sort"` @@ -274,37 +276,37 @@ type ( Host string `json:"host"` ServiceName string `json:"service_name"` } - Server { - Id int64 `json:"id"` - Tags []string `json:"tags"` - Country string `json:"country"` - City string `json:"city"` - Name string `json:"name"` - ServerAddr string `json:"server_addr"` - RelayMode string `json:"relay_mode"` - RelayNode []NodeRelay `json:"relay_node"` - SpeedLimit int `json:"speed_limit"` - TrafficRatio float32 `json:"traffic_ratio"` - GroupId int64 `json:"group_id"` - Protocol string `json:"protocol"` - Config interface{} `json:"config"` - Enable *bool `json:"enable"` - CreatedAt int64 `json:"created_at"` - UpdatedAt int64 `json:"updated_at"` - Status *NodeStatus `json:"status"` - Sort int64 `json:"sort"` - } - OnlineUser { - SID int64 `json:"uid"` - IP string `json:"ip"` - } - NodeStatus { - Online interface{} `json:"online"` - Cpu float64 `json:"cpu"` - Mem float64 `json:"mem"` - Disk float64 `json:"disk"` - UpdatedAt int64 `json:"updated_at"` - } + // Server { + // Id int64 `json:"id"` + // Tags []string `json:"tags"` + // Country string `json:"country"` + // City string `json:"city"` + // Name string `json:"name"` + // ServerAddr string `json:"server_addr"` + // RelayMode string `json:"relay_mode"` + // RelayNode []NodeRelay `json:"relay_node"` + // SpeedLimit int `json:"speed_limit"` + // TrafficRatio float32 `json:"traffic_ratio"` + // GroupId int64 `json:"group_id"` + // Protocol string `json:"protocol"` + // Config interface{} `json:"config"` + // Enable *bool `json:"enable"` + // CreatedAt int64 `json:"created_at"` + // UpdatedAt int64 `json:"updated_at"` + // Status *NodeStatus `json:"status"` + // Sort int64 `json:"sort"` + // } + // OnlineUser { + // SID int64 `json:"uid"` + // IP string `json:"ip"` + // } + // NodeStatus { + // Online interface{} `json:"online"` + // Cpu float64 `json:"cpu"` + // Mem float64 `json:"mem"` + // Disk float64 `json:"disk"` + // UpdatedAt int64 `json:"updated_at"` + // } ServerGroup { Id int64 `json:"id"` Name string `json:"name"` @@ -446,15 +448,6 @@ type ( CreatedAt int64 `json:"created_at"` UpdatedAt int64 `json:"updated_at"` } - UserBalanceLog { - Id int64 `json:"id"` - UserId int64 `json:"user_id"` - Amount int64 `json:"amount"` - Type uint8 `json:"type"` - OrderId int64 `json:"order_id"` - Balance int64 `json:"balance"` - CreatedAt int64 `json:"created_at"` - } UserAffiliate { Avatar string `json:"avatar"` Identifier string `json:"identifier"` @@ -475,14 +468,6 @@ type ( Port int `json:"port"` Prefix string `json:"prefix"` } - ApplicationConfig { - AppId int64 `json:"app_id"` - EncryptionKey string `json:"encryption_key"` - EncryptionMethod string `json:"encryption_method"` - Domains []string `json:"domains" validate:"required"` - StartupPicture string `json:"startup_picture"` - StartupPictureSkipTime int64 `json:"startup_picture_skip_time"` - } UserDevice { Id int64 `json:"id"` Ip string `json:"ip"` @@ -532,7 +517,7 @@ type ( Token string `json:"token"` IP string `json:"ip"` UserAgent string `json:"user_agent"` - CreatedAt int64 `json:"created_at"` + Timestamp int64 `json:"timestamp"` } UserLoginLog { Id int64 `json:"id"` @@ -540,18 +525,17 @@ type ( LoginIP string `json:"login_ip"` UserAgent string `json:"user_agent"` Success bool `json:"success"` - CreatedAt int64 `json:"created_at"` + Timestamp int64 `json:"timestamp"` } MessageLog { - Id int64 `json:"id"` - Type string `json:"type"` - Platform string `json:"platform"` - To string `json:"to"` - Subject string `json:"subject"` - Content string `json:"content"` - Status int `json:"status"` - CreatedAt int64 `json:"created_at"` - UpdatedAt int64 `json:"updated_at"` + Id int64 `json:"id"` + Type uint8 `json:"type"` + Platform string `json:"platform"` + To string `json:"to"` + Subject string `json:"subject"` + Content interface{} `json:"content"` + Status uint8 `json:"status"` + CreatedAt int64 `json:"created_at"` } Ads { Id int `json:"id"` @@ -763,5 +747,60 @@ type ( Linux string `json:"linux,omitempty"` Harmony string `json:"harmony,omitempty"` } + ResetSubscribeTrafficLog { + Id int64 `json:"id"` + Type uint16 `json:"type"` + UserSubscribeId int64 `json:"user_subscribe_id"` + OrderNo string `json:"order_no,omitempty"` + Timestamp int64 `json:"timestamp"` + } + BalanceLog { + Type uint16 `json:"type"` + UserId int64 `json:"user_id"` + Amount int64 `json:"amount"` + OrderNo string `json:"order_no,omitempty"` + Balance int64 `json:"balance"` + Timestamp int64 `json:"timestamp"` + } + CommissionLog { + Type uint16 `json:"type"` + UserId int64 `json:"user_id"` + Amount int64 `json:"amount"` + OrderNo string `json:"order_no"` + Timestamp int64 `json:"timestamp"` + } + Protocol { + Type string `json:"type"` + Port uint16 `json:"port"` + Security string `json:"security,omitempty"` + SNI string `json:"sni,omitempty"` + AllowInsecure bool `json:"allow_insecure,omitempty"` + Fingerprint string `json:"fingerprint,omitempty"` + RealityServerAddr string `json:"reality_server_addr,omitempty"` + RealityServerPort int `json:"reality_server_port,omitempty"` + RealityPrivateKey string `json:"reality_private_key,omitempty"` + RealityPublicKey string `json:"reality_public_key,omitempty"` + RealityShortId string `json:"reality_short_id,omitempty"` + Transport string `json:"transport,omitempty"` + Host string `json:"host,omitempty"` + Path string `json:"path,omitempty"` + ServiceName string `json:"service_name,omitempty"` + Cipher string `json:"cipher,omitempty"` + ServerKey string `json:"server_key,omitempty"` + Flow string `json:"flow,omitempty"` + HopPorts string `json:"hop_ports,omitempty"` + HopInterval int `json:"hop_interval,omitempty"` + ObfsPassword string `json:"obfs_password,omitempty"` + DisableSNI bool `json:"disable_sni,omitempty"` + ReduceRtt bool `json:"reduce_rtt,omitempty"` + UDPRelayMode string `json:"udp_relay_mode,omitempty"` + CongestionController string `json:"congestion_controller,omitempty"` + Plugin string `json:"plugin,omitempty"` // obfs, none,v2ray-plugin, simple-obfs + PluginOptions string `json:"plugin_options,omitempty"` // plugin options, eg: obfs=http;obfs-host=www.bing.com + Multiplex string `json:"multiplex,omitempty"` // mux, eg: off/low/medium/high + PaddingScheme string `json:"padding_scheme,omitempty"` // padding scheme + UpMbps int `json:"up_mbps,omitempty"` // upload speed limit + DownMbps int `json:"down_mbps,omitempty"` // download speed limit + } ) diff --git a/go.mod b/go.mod index c0145a7..04daadd 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/go-sql-driver/mysql v1.8.1 github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 github.com/gofrs/uuid/v5 v5.3.0 - github.com/golang-jwt/jwt/v5 v5.2.1 + github.com/golang-jwt/jwt/v5 v5.2.2 github.com/google/uuid v1.6.0 github.com/gorilla/websocket v1.5.3 github.com/hibiken/asynq v0.24.1 @@ -28,7 +28,7 @@ require ( github.com/klauspost/compress v1.17.7 github.com/nyaruka/phonenumbers v1.5.0 github.com/pkg/errors v0.9.1 - github.com/redis/go-redis/v9 v9.6.1 + github.com/redis/go-redis/v9 v9.7.2 github.com/smartwalle/alipay/v3 v3.2.23 github.com/spf13/cast v1.7.0 // indirect github.com/spf13/cobra v1.8.1 diff --git a/go.sum b/go.sum index cc90adf..9e9f2c5 100644 --- a/go.sum +++ b/go.sum @@ -155,8 +155,8 @@ github.com/gofrs/uuid/v5 v5.3.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= -github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= +github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-migrate/migrate/v4 v4.18.2 h1:2VSCMz7x7mjyTXx3m2zPokOY82LTRgxK1yQYKo6wWQ8= github.com/golang-migrate/migrate/v4 v4.18.2/go.mod h1:2CM6tJvn2kqPXwnXO/d3rAQYiyoIm180VsO8PRX6Rpk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -294,8 +294,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/redis/go-redis/v9 v9.0.3/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= -github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4= -github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA= +github.com/redis/go-redis/v9 v9.7.2 h1:PSGhv13dJyrTCw1+55H0pIKM3WFov7HuUrKUmInGL0o= +github.com/redis/go-redis/v9 v9.7.2/go.mod h1:yp5+a5FnEEP0/zTYuw6u6/2nn3zivwhv274qYgWQhDM= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= diff --git a/initialize/init.go b/initialize/init.go index bad262f..02ce905 100644 --- a/initialize/init.go +++ b/initialize/init.go @@ -14,7 +14,6 @@ func StartInitSystemConfig(svc *svc.ServiceContext) { Subscribe(svc) Register(svc) Mobile(svc) - TrafficDataToRedis(svc) if !svc.Config.Debug { Telegram(svc) } diff --git a/initialize/migrate/database/02101_subscribe_application.up.sql b/initialize/migrate/database/02101_subscribe_application.up.sql index 5bb2e79..dc3f841 100644 --- a/initialize/migrate/database/02101_subscribe_application.up.sql +++ b/initialize/migrate/database/02101_subscribe_application.up.sql @@ -19,9 +19,9 @@ CREATE TABLE IF NOT EXISTS `subscribe_application` ( -- Records of subscribe_application -- ---------------------------- BEGIN; -INSERT INTO `subscribe_application` (`id`, `name`, `icon`, `description`, `scheme`, `user_agent`, `is_default`, `subscribe_template`, `output_format`, `download_link`, `created_at`, `updated_at`) VALUES (1, 'Default', '', '', '', 'default', 1, '{{- range $n := .Proxies }}\n {{- $dn := urlquery (default \"node\" $n.Name) -}}\n {{- $sni := default $n.Host $n.SNI -}}\n\n {{- if eq $n.Type \"shadowsocks\" -}}\n {{- $userinfo := b64enc (print $n.Method \":\" $.UserInfo.Password) -}}\n {{- printf \"ss://%s@%s:%v#%s\" $userinfo $n.Host $n.Port $dn -}}\n {{- \"\\n\" -}}\n {{- end -}}\n\n {{- if eq $n.Type \"trojan\" -}}\n {{- $qs := \"security=tls\" -}}\n {{- if $sni }}{{ $qs = printf \"%s&sni=%s\" $qs (urlquery $sni) }}{{ end -}}\n {{- if $n.AllowInsecure }}{{ $qs = printf \"%s&allowInsecure=%v\" $qs $n.AllowInsecure }}{{ end -}}\n {{- if $n.Fingerprint }}{{ $qs = printf \"%s&fp=%s\" $qs (urlquery $n.Fingerprint) }}{{ end -}}\n {{- printf \"trojan://%s@%s:%v?%s#%s\" $.UserInfo.Password $n.Host $n.Port $qs $dn -}}\n {{- \"\\n\" -}}\n {{- end -}}\n\n {{- if eq $n.Type \"vless\" -}}\n {{- $qs := \"encryption=none\" -}}\n {{- if $n.RealityPublicKey -}}\n {{- $qs = printf \"%s&security=reality\" $qs -}}\n {{- $qs = printf \"%s&pbk=%s\" $qs (urlquery $n.RealityPublicKey) -}}\n {{- if $n.RealityShortId }}{{ $qs = printf \"%s&sid=%s\" $qs (urlquery $n.RealityShortId) }}{{ end -}}\n {{- else -}}\n {{- if or $n.SNI $n.Fingerprint $n.AllowInsecure }}\n {{- $qs = printf \"%s&security=tls\" $qs -}}\n {{- end -}}\n {{- end -}}\n {{- if $n.SNI }}{{ $qs = printf \"%s&sni=%s\" $qs (urlquery $n.SNI) }}{{ end -}}\n {{- if $n.AllowInsecure }}{{ $qs = printf \"%s&allowInsecure=%v\" $qs $n.AllowInsecure }}{{ end -}}\n {{- if $n.Fingerprint }}{{ $qs = printf \"%s&fp=%s\" $qs (urlquery $n.Fingerprint) }}{{ end -}}\n {{- if $n.Network }}{{ $qs = printf \"%s&type=%s\" $qs $n.Network }}{{ end -}}\n {{- if $n.Path }}{{ $qs = printf \"%s&path=%s\" $qs (urlquery $n.Path) }}{{ end -}}\n {{- if $n.ServiceName }}{{ $qs = printf \"%s&serviceName=%s\" $qs (urlquery $n.ServiceName) }}{{ end -}}\n {{- if $n.Flow }}{{ $qs = printf \"%s&flow=%s\" $qs (urlquery $n.Flow) }}{{ end -}}\n {{- printf \"vless://%s@%s:%v?%s#%s\" $n.ServerKey $n.Host $n.Port $qs $dn -}}\n {{- \"\\n\" -}}\n {{- end -}}\n\n {{- if eq $n.Type \"vmess\" -}}\n {{- $obj := dict\n \"v\" \"2\"\n \"ps\" $n.Name\n \"add\" $n.Host\n \"port\" $n.Port\n \"id\" $n.ServerKey\n \"aid\" 0\n \"net\" (or $n.Network \"tcp\")\n \"type\" \"none\"\n \"path\" (or $n.Path \"\")\n \"host\" $n.Host\n -}}\n {{- if or $n.SNI $n.Fingerprint $n.AllowInsecure }}{{ $_ := set $obj \"tls\" \"tls\" }}{{ end -}}\n {{- if $n.SNI }}{{ $_ := set $obj \"sni\" $n.SNI }}{{ end -}}\n {{- if $n.Fingerprint }}{{ $_ := set $obj \"fp\" $n.Fingerprint }}{{ end -}}\n {{- printf \"vmess://%s\" (b64enc (toJson $obj)) -}}\n {{- \"\\n\" -}}\n {{- end -}}\n\n {{- if or (eq $n.Type \"hysteria2\") (eq $n.Type \"hy2\") -}}\n {{- $qs := \"\" -}}\n {{- if $n.SNI }}{{ $qs = printf \"sni=%s\" (urlquery $n.SNI) }}{{ end -}}\n {{- if $n.AllowInsecure }}{{ $qs = printf \"%s&insecure=%v\" $qs $n.AllowInsecure }}{{ end -}}\n {{- if $n.ObfsPassword }}{{ $qs = printf \"%s&obfs-password=%s\" $qs (urlquery $n.ObfsPassword) }}{{ end -}}\n {{- printf \"hy2://%s@%s:%v\" $.UserInfo.Password $n.Host $n.Port -}}\n {{- if gt (len $qs) 0 -}}?{{ $qs }}{{- end -}}\n {{- printf \"#%s\" $dn -}}\n {{- \"\\n\" -}}\n {{- end -}}\n\n {{- if eq $n.Type \"tuic\" -}}\n {{- $qs := \"\" -}}\n {{- if $n.SNI }}{{ $qs = printf \"sni=%s\" (urlquery $n.SNI) }}{{ end -}}\n {{- if $n.AllowInsecure }}{{ $qs = printf \"%s&insecure=%v\" $qs $n.AllowInsecure }}{{ end -}}\n {{- printf \"tuic://%s:%s@%s:%v\" $n.ServerKey $.UserInfo.Password $n.Host $n.Port -}}\n {{- if gt (len $qs) 0 -}}?{{ $qs }}{{- end -}}\n {{- printf \"#%s\" $dn -}}\n {{- \"\\n\" -}}\n {{- end -}}\n\n {{- if eq $n.Type \"anytls\" -}}\n {{- $qs := \"\" -}}\n {{- if $n.SNI }}{{ $qs = printf \"sni=%s\" (urlquery $n.SNI) }}{{ end -}}\n {{- printf \"anytls://%s@%s:%v\" $.UserInfo.Password $n.Host $n.Port -}}\n {{- if gt (len $qs) 0 -}}?{{ $qs }}{{- end -}}\n {{- printf \"#%s\" $dn -}}\n {{- \"\\n\" -}}\n {{- end -}}\n\n{{- end }}', 'base64', '{}', '2025-08-12 22:57:56.711', '2025-08-15 21:45:20.181'); -INSERT INTO `subscribe_application` (`id`, `name`, `icon`, `description`, `scheme`, `user_agent`, `is_default`, `subscribe_template`, `output_format`, `download_link`, `created_at`, `updated_at`) VALUES (2, 'Shadowsocket', '', '', 'shadowrocket://add/sub://${window.btoa(url)}?remark=${encodeURIComponent(name)}', 'Shadowsocket', 0, '{{- $GiB := 1073741824.0 -}}\n{{- $used := printf \"%.2f\" (divf (add (.UserInfo.Download | default 0 | float64) (.UserInfo.Upload | default 0 | float64)) $GiB) -}}\n{{- $total := printf \"%.2f\" (divf (.UserInfo.Traffic | default 0 | float64) $GiB) -}}\n\n{{- $exp := \"\" -}}\n{{- if or (kindIs \"int\" .UserInfo.ExpiredAt) (kindIs \"int64\" .UserInfo.ExpiredAt) (kindIs \"float64\" .UserInfo.ExpiredAt) -}}\n {{- $exp = (date \"2006-01-02 15:04:05\" (unixEpoch .UserInfo.ExpiredAt)) -}}\n{{- else -}}\n {{- $expStr := printf \"%v\" .UserInfo.ExpiredAt -}}\n {{- if regexMatch `^[0-9]+$` $expStr -}}\n {{- $ts := $expStr | int64 -}}\n {{- $sec := ternary (divf ($ts | float64) 1000.0 | int64) $ts (ge (len $expStr) 13) -}}\n {{- $exp = (date \"2006-01-02 15:04:05\" (unixEpoch $sec)) -}}\n {{- else if regexMatch `^[0-9]{4}-[0-9]{2}-[0-9]{2}$` $expStr -}}\n {{- $exp = (printf \"%s 00:00:00\" $expStr) -}}\n {{- else if regexMatch `^[0-9]{4}-[0-9]{2}-[0-9]{2}[ T][0-9]{2}:[0-9]{2}:[0-9]{2}$` $expStr -}}\n {{- $exp = (replace $expStr \"T\" \" \") -}}\n {{- else if regexMatch `^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}.*` $expStr -}}\n {{- $t := mustToDate \"2006-01-02T15:04:05Z07:00\" $expStr -}}\n {{- $exp = (date \"2006-01-02 15:04:05\" $t) -}}\n {{- else -}}\n {{- $exp = $expStr -}}\n {{- end -}}\n{{- end -}}\n\nREMARKS={{ .SiteName }}-{{ .SubscribeName }}\nSTATUS=Traffic: {{ $used }} GiB/{{ $total }} GiB | Expires: {{ $exp }}\n{{ range $n := .Proxies }}\n {{- $dn := default \"node\" $n.Name -}}\n {{- $sni := default $n.Host $n.SNI -}}\n {{- $common := \"udp=1&tfo=1\" -}}\n\n {{- if eq $n.Type \"shadowsocks\" -}}\n {{- $userinfo := b64enc (print $n.Method \":\" $.UserInfo.Password) -}}\n {{- printf \"ss://%s@%s:%v?%s#%s\" $userinfo $n.Host $n.Port $common $dn -}}\n {{- \"\\n\" -}}\n {{- end -}}\n\n {{- if eq $n.Type \"trojan\" -}}\n {{- $qs := printf \"security=tls&%s\" $common -}}\n {{- if $sni }}{{ $qs = printf \"%s&sni=%s\" $qs (urlquery $sni) }}{{ end -}}\n {{- if $n.AllowInsecure }}{{ $qs = printf \"%s&allowInsecure=%v\" $qs $n.AllowInsecure }}{{ end -}}\n {{- if $n.Fingerprint }}{{ $qs = printf \"%s&fp=%s\" $qs (urlquery $n.Fingerprint) }}{{ end -}}\n {{- printf \"trojan://%s@%s:%v?%s#%s\" $.UserInfo.Password $n.Host $n.Port $qs $dn -}}\n {{- \"\\n\" -}}\n {{- end -}}\n\n {{- if eq $n.Type \"vless\" -}}\n {{- $qs := printf \"encryption=none&%s\" $common -}}\n {{- if $n.RealityPublicKey -}}\n {{- $qs = printf \"%s&security=reality\" $qs -}}\n {{- $qs = printf \"%s&pbk=%s\" $qs (urlquery $n.RealityPublicKey) -}}\n {{- if $n.RealityShortId }}{{ $qs = printf \"%s&sid=%s\" $qs (urlquery $n.RealityShortId) }}{{ end -}}\n {{- else -}}\n {{- if or $n.SNI $n.Fingerprint $n.AllowInsecure }}\n {{- $qs = printf \"%s&security=tls\" $qs -}}\n {{- end -}}\n {{- end -}}\n {{- if $n.SNI }}{{ $qs = printf \"%s&sni=%s\" $qs (urlquery $n.SNI) }}{{ end -}}\n {{- if $n.AllowInsecure }}{{ $qs = printf \"%s&allowInsecure=%v\" $qs $n.AllowInsecure }}{{ end -}}\n {{- if $n.Fingerprint }}{{ $qs = printf \"%s&fp=%s\" $qs (urlquery $n.Fingerprint) }}{{ end -}}\n {{- if $n.Network }}{{ $qs = printf \"%s&type=%s\" $qs $n.Network }}{{ end -}}\n {{- if $n.Path }}{{ $qs = printf \"%s&path=%s\" $qs (urlquery $n.Path) }}{{ end -}}\n {{- if $n.ServiceName }}{{ $qs = printf \"%s&serviceName=%s\" $qs (urlquery $n.ServiceName) }}{{ end -}}\n {{- if $n.Flow }}{{ $qs = printf \"%s&flow=%s\" $qs (urlquery $n.Flow) }}{{ end -}}\n {{- printf \"vless://%s@%s:%v?%s#%s\" $n.ServerKey $n.Host $n.Port $qs $dn -}}\n {{- \"\\n\" -}}\n {{- end -}}\n\n {{- if eq $n.Type \"vmess\" -}}\n {{- $obj := dict\n \"v\" \"2\"\n \"ps\" $n.Name\n \"add\" $n.Host\n \"port\" $n.Port\n \"id\" $n.ServerKey\n \"aid\" 0\n \"net\" (or $n.Network \"tcp\")\n \"type\" \"none\"\n \"path\" (or $n.Path \"\")\n \"host\" $n.Host\n -}}\n {{- if or $n.SNI $n.Fingerprint $n.AllowInsecure }}{{ $_ := set $obj \"tls\" \"tls\" }}{{ end -}}\n {{- if $n.SNI }}{{ $_ := set $obj \"sni\" $n.SNI }}{{ end -}}\n {{- if $n.Fingerprint }}{{ $_ := set $obj \"fp\" $n.Fingerprint }}{{ end -}}\n {{- printf \"vmess://%s\" (b64enc (toJson $obj)) -}}\n {{- \"\\n\" -}}\n {{- end -}}\n\n {{- if or (eq $n.Type \"hysteria2\") (eq $n.Type \"hy2\") -}}\n {{- $qs := $common -}}\n {{- if $n.SNI }}{{ $qs = printf \"%s&sni=%s\" $qs (urlquery $n.SNI) }}{{ end -}}\n {{- if $n.AllowInsecure }}{{ $qs = printf \"%s&insecure=%v\" $qs $n.AllowInsecure }}{{ end -}}\n {{- if $n.ObfsPassword }}{{ $qs = printf \"%s&obfs-password=%s\" $qs (urlquery $n.ObfsPassword) }}{{ end -}}\n {{- if $n.HopPorts }}{{ $qs = printf \"%s&hop-ports=%s\" $qs (urlquery $n.HopPorts) }}{{ end -}}\n {{- if $n.HopInterval }}{{ $qs = printf \"%s&hop-interval=%v\" $qs $n.HopInterval }}{{ end -}}\n {{- printf \"hy2://%s@%s:%v?%s#%s\" $.UserInfo.Password $n.Host $n.Port $qs $dn -}}\n {{- \"\\n\" -}}\n {{- end -}}\n\n {{- if eq $n.Type \"tuic\" -}}\n {{- $qs := $common -}}\n {{- if $n.SNI }}{{ $qs = printf \"%s&sni=%s\" $qs (urlquery $n.SNI) }}{{ end -}}\n {{- if $n.AllowInsecure }}{{ $qs = printf \"%s&insecure=%v\" $qs $n.AllowInsecure }}{{ end -}}\n {{- if $n.DisableSNI }}{{ $qs = printf \"%s&disable-sni=%v\" $qs $n.DisableSNI }}{{ end -}}\n {{- if $n.ReduceRtt }}{{ $qs = printf \"%s&reduce-rtt=%v\" $qs $n.ReduceRtt }}{{ end -}}\n {{- if $n.UDPRelayMode }}{{ $qs = printf \"%s&udp-relay-mode=%s\" $qs (urlquery $n.UDPRelayMode) }}{{ end -}}\n {{- if $n.CongestionController }}{{ $qs = printf \"%s&congestion-controller=%s\" $qs (urlquery $n.CongestionController) }}{{ end -}}\n {{- printf \"tuic://%s:%s@%s:%v?%s#%s\" $n.ServerKey $.UserInfo.Password $n.Host $n.Port $qs $dn -}}\n {{- \"\\n\" -}}\n {{- end -}}\n\n {{- if eq $n.Type \"anytls\" -}}\n {{- $qs := $common -}}\n {{- if $n.SNI }}{{ $qs = printf \"%s&sni=%s\" $qs (urlquery $n.SNI) }}{{ end -}}\n {{- printf \"anytls://%s@%s:%v?%s#%s\" $.UserInfo.Password $n.Host $n.Port $qs $dn -}}\n {{- \"\\n\" -}}\n {{- end -}}\n\n{{- end }}', 'base64', '{}', '2025-08-12 23:03:50.004', '2025-08-15 22:01:39.221'); -INSERT INTO `subscribe_application` (`id`, `name`, `icon`, `description`, `scheme`, `user_agent`, `is_default`, `subscribe_template`, `output_format`, `download_link`, `created_at`, `updated_at`) VALUES (3, 'Clash', '', '', 'clash://install-config?url=${url}&name=${name}', 'Clash', 0, 'port: 8888\nsocks-port: 8889\nmixed-port: 8899\nallow-lan: true\nmode: Rule\nlog-level: info\nexternal-controller: \'127.0.0.1:6170\'\nsecret: {{ .SiteName }}\nexperimental:\n ignore-resolve-fail: true\ncfw-latency-url: \'http://cp.cloudflare.com/generate_204\'\ncfw-latency-timeout: 3000\ncfw-latency-type: 1\ncfw-conn-break-strategy: true\nclash-for-android:\n ui-subtitle-pattern: \'\'\nurl-rewrite:\n - \'^https?:\\/\\/(www.)?(g|google)\\.cn https://www.google.com 302\'\n - \'^https?:\\/\\/(ditu|maps).google\\.cn https://maps.google.com 302\'\nproxies:\n{{- range $proxy := .Proxies }}\n {{- if eq $proxy.Type \"shadowsocks\" }}\n - { name: \'{{ $proxy.Name }}\', type: ss, server: {{ $proxy.Host }}, port: {{ $proxy.Port }}, cipher: {{ default \"aes-128-gcm\" $proxy.Method }}, password: {{ $.UserInfo.Password }}, udp: false{{- if $proxy.Network }}, plugin: obfs, plugin-opts: { mode: http, host: {{ $proxy.SNI | default $proxy.Host }} }{{ end }} }\n {{- else if eq $proxy.Type \"trojan\" }}\n - { name: \'{{ $proxy.Name }}\', type: trojan, server: {{ $proxy.Host }}, port: {{ $proxy.Port }}, password: {{ $.UserInfo.Password }}{{- if $proxy.SNI }}, sni: {{ $proxy.SNI }}{{ end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify: {{ $proxy.AllowInsecure }}{{ end }}{{- if $proxy.Fingerprint }}, fingerprint: {{ $proxy.Fingerprint }}{{ end }} }\n {{- else if eq $proxy.Type \"vless\" }}\n - { name: \'{{ $proxy.Name }}\', type: vless, server: {{ $proxy.Host }}, port: {{ $proxy.Port }}, uuid: {{ $proxy.ServerKey }}, udp: true{{- if $proxy.Network }}, network: {{ $proxy.Network }}{{ end }}{{- if $proxy.Path }}, ws-opts: { path: {{ $proxy.Path }} }{{ end }}{{- if $proxy.ServiceName }}, grpc-opts: { grpc-service-name: {{ $proxy.ServiceName }} }{{ end }}{{- if $proxy.SNI }}, servername: {{ $proxy.SNI }}{{ end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify: {{ $proxy.AllowInsecure }}{{ end }}{{- if $proxy.Fingerprint }}, fingerprint: {{ $proxy.Fingerprint }}{{ end }}{{- if $proxy.RealityPublicKey }}, reality-opts: { public-key: {{ $proxy.RealityPublicKey }}{{- if $proxy.RealityShortId }}, short-id: {{ $proxy.RealityShortId }}{{ end }} }{{ end }}{{- if $proxy.Flow }}, flow: {{ $proxy.Flow }}{{ end }} }\n {{- else if eq $proxy.Type \"vmess\" }}\n - { name: \'{{ $proxy.Name }}\', type: vmess, server: {{ $proxy.Host }}, port: {{ $proxy.Port }}, uuid: {{ $proxy.ServerKey }}, alterId: 0, cipher: auto, udp: true{{- if $proxy.Network }}, network: {{ $proxy.Network }}{{ end }}{{- if $proxy.Path }}, ws-opts: { path: {{ $proxy.Path }} }{{ end }}{{- if $proxy.SNI }}, servername: {{ $proxy.SNI }}{{ end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify: {{ $proxy.AllowInsecure }}{{ end }}{{- if $proxy.Fingerprint }}, fingerprint: {{ $proxy.Fingerprint }}{{ end }} }\n {{- else if or (eq $proxy.Type \"hysteria2\") (eq $proxy.Type \"hy2\") }}\n - { name: \'{{ $proxy.Name }}\', type: hysteria2, server: {{ $proxy.Host }}, port: {{ $proxy.Port }}, password: {{ $.UserInfo.Password }}{{- if $proxy.SNI }}, sni: {{ $proxy.SNI }}{{ end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify: {{ $proxy.AllowInsecure }}{{ end }}{{- if $proxy.ObfsPassword }}, obfs: salamander, obfs-password: {{ $proxy.ObfsPassword }}{{ end }} }\n {{- else if eq $proxy.Type \"tuic\" }}\n - { name: \'{{ $proxy.Name }}\', type: tuic, server: {{ $proxy.Host }}, port: {{ $proxy.Port }}, uuid: {{ $proxy.ServerKey }}, password: {{ $.UserInfo.Password }}{{- if $proxy.SNI }}, sni: {{ $proxy.SNI }}{{ end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify: {{ $proxy.AllowInsecure }}{{ end }} }\n {{- else if eq $proxy.Type \"wireguard\" }}\n - { name: \'{{ $proxy.Name }}\', type: wireguard, server: {{ $proxy.Host }}, port: {{ $proxy.Port }}, private-key: {{ $proxy.ServerKey }}, public-key: {{ $proxy.RealityPublicKey }}{{- if $proxy.Path }}, preshared-key: {{ $proxy.Path }}{{ end }} }\n {{- else }}\n - { name: \'{{ $proxy.Name }}\', type: {{ $proxy.Type }}, server: {{ $proxy.Host }}, port: {{ $proxy.Port }} }\n {{- end }}\n{{- end }}\nproxy-groups:\n - { name: Proxy, type: select, proxies: [\'Auto - UrlTest\', DIRECT{{- range $proxy := .Proxies }}, \'{{ $proxy.Name }}\'{{- end }}] }\n - { name: Domestic, type: select, proxies: [DIRECT, Proxy{{- range $proxy := .Proxies }}, \'{{ $proxy.Name }}\'{{- end }}] }\n - { name: Others, type: select, proxies: [Proxy, DIRECT{{- range $proxy := .Proxies }}, \'{{ $proxy.Name }}\'{{- end }}] }\n - { name: AdBlock, type: select, proxies: [REJECT, DIRECT, Proxy] }\n - { name: HTTPDNS, type: select, proxies: [DIRECT, REJECT, Proxy] }\n - { name: Netflix, type: select, proxies: [Proxy, DIRECT{{- range $proxy := .Proxies }}, \'{{ $proxy.Name }}\'{{- end }}] }\n - { name: \'Disney Plus\', type: select, proxies: [Proxy, DIRECT{{- range $proxy := .Proxies }}, \'{{ $proxy.Name }}\'{{- end }}] }\n - { name: YouTube, type: select, proxies: [Proxy, DIRECT{{- range $proxy := .Proxies }}, \'{{ $proxy.Name }}\'{{- end }}] }\n - { name: Max, type: select, proxies: [Proxy, DIRECT{{- range $proxy := .Proxies }}, \'{{ $proxy.Name }}\'{{- end }}] }\n - { name: Spotify, type: select, proxies: [Proxy, DIRECT{{- range $proxy := .Proxies }}, \'{{ $proxy.Name }}\'{{- end }}] }\n - { name: \'CN Mainland TV\', type: select, proxies: [DIRECT, Proxy{{- range $proxy := .Proxies }}, \'{{ $proxy.Name }}\'{{- end }}] }\n - { name: \'Asian TV\', type: select, proxies: [Proxy, DIRECT{{- range $proxy := .Proxies }}, \'{{ $proxy.Name }}\'{{- end }}] }\n - { name: \'Global TV\', type: select, proxies: [Proxy, DIRECT{{- range $proxy := .Proxies }}, \'{{ $proxy.Name }}\'{{- end }}] }\n - { name: \'Auto - UrlTest\', type: url-test, proxies: [{{- range $i, $proxy := .Proxies }}{{- if gt $i 0 }}, {{ end }}\'{{ $proxy.Name }}\'{{- end }}], url: \'http://cp.cloudflare.com/generate_204\', interval: \'3600\' }\nrrules:\n - DOMAIN-SUFFIX,local,DIRECT\n - IP-CIDR,192.168.0.0/16,DIRECT,no-resolve\n - IP-CIDR,10.0.0.0/8,DIRECT,no-resolve\n - IP-CIDR,172.16.0.0/12,DIRECT,no-resolve\n - IP-CIDR,127.0.0.0/8,DIRECT,no-resolve\n - IP-CIDR,100.64.0.0/10,DIRECT,no-resolve\n - IP-CIDR6,::1/128,DIRECT,no-resolve\n - IP-CIDR6,fc00::/7,DIRECT,no-resolve\n - IP-CIDR6,fe80::/10,DIRECT,no-resolve\n - IP-CIDR6,fd00::/8,DIRECT,no-resolve\n - DOMAIN-SUFFIX,acm.org,Scholar\n - DOMAIN-SUFFIX,acs.org,Scholar\n - DOMAIN-SUFFIX,aip.org,Scholar\n - DOMAIN-SUFFIX,ams.org,Scholar\n - DOMAIN-SUFFIX,annualreviews.org,Scholar\n - DOMAIN-SUFFIX,aps.org,Scholar\n - DOMAIN-SUFFIX,ascelibrary.org,Scholar\n - DOMAIN-SUFFIX,asm.org,Scholar\n - DOMAIN-SUFFIX,asme.org,Scholar\n - DOMAIN-SUFFIX,astm.org,Scholar\n - DOMAIN-SUFFIX,blackwell-synergy.com,Scholar\n - DOMAIN-SUFFIX,bmj.com,Scholar\n - DOMAIN-SUFFIX,cabdirect.org,Scholar\n - DOMAIN-SUFFIX,cambridge.org,Scholar\n - DOMAIN-SUFFIX,cas.org,Scholar\n - DOMAIN-SUFFIX,cell.com,Scholar\n - DOMAIN-SUFFIX,clarivate.com,Scholar\n - DOMAIN-SUFFIX,csiro.au,Scholar\n - DOMAIN-SUFFIX,deepdyve.com,Scholar\n - DOMAIN-SUFFIX,ebscohost.com,Scholar\n - DOMAIN-SUFFIX,els-cdn.com,Scholar\n - DOMAIN-SUFFIX,elsevier.com,Scholar\n - DOMAIN-SUFFIX,emerald.com,Scholar\n - DOMAIN-SUFFIX,endnote.com,Scholar\n - DOMAIN-SUFFIX,engineeringvillage.com,Scholar\n - DOMAIN-SUFFIX,icevirtuallibrary.com,Scholar\n - DOMAIN-SUFFIX,ieee.org,Scholar\n - DOMAIN-SUFFIX,imf.org,Scholar\n - DOMAIN-SUFFIX,iop.org,Scholar\n - DOMAIN-SUFFIX,jamanetwork.com,Scholar\n - DOMAIN-SUFFIX,jbc.org,Scholar\n - DOMAIN-SUFFIX,jhu.edu,Scholar\n - DOMAIN-SUFFIX,jstor.org,Scholar\n - DOMAIN-SUFFIX,karger.com,Scholar\n - DOMAIN-SUFFIX,libguides.com,Scholar\n - DOMAIN-SUFFIX,liebertpub.com,Scholar\n - DOMAIN-SUFFIX,madsrevolution.net,Scholar\n - DOMAIN-SUFFIX,mdpi.com,Scholar\n - DOMAIN-SUFFIX,mpg.de,Scholar\n - DOMAIN-SUFFIX,myilibrary.com,Scholar\n - DOMAIN-SUFFIX,nature.com,Scholar\n - DOMAIN-SUFFIX,ncbi.nlm.nih.gov,Scholar\n - DOMAIN-SUFFIX,oecd-ilibrary.org,Scholar\n - DOMAIN-SUFFIX,osapublishing.org,Scholar\n - DOMAIN-SUFFIX,oup.com,Scholar\n - DOMAIN-SUFFIX,ovid.com,Scholar\n - DOMAIN-SUFFIX,oxfordartonline.com,Scholar\n - DOMAIN-SUFFIX,oxfordbibliographies.com,Scholar\n - DOMAIN-SUFFIX,oxfordmusiconline.com,Scholar\n - DOMAIN-SUFFIX,pnas.org,Scholar\n - DOMAIN-SUFFIX,proquest.com,Scholar\n - DOMAIN-SUFFIX,readcube.com,Scholar\n - DOMAIN-SUFFIX,researchgate.net,Scholar\n - DOMAIN-SUFFIX,royalsocietypublishing.org,Scholar\n - DOMAIN-SUFFIX,rsc.org,Scholar\n - DOMAIN-SUFFIX,sagepub.com,Scholar\n - DOMAIN-SUFFIX,sci-hub.tw,Scholar\n - DOMAIN-SUFFIX,sciencedirect.com,Scholar\n - DOMAIN-SUFFIX,science.org,Scholar\n - DOMAIN-SUFFIX,scitation.org,Scholar\n - DOMAIN-SUFFIX,scopus.com,Scholar\n - DOMAIN-SUFFIX,semanticscholar.org,Scholar\n - DOMAIN-SUFFIX,siam.org,Scholar\n - DOMAIN-SUFFIX,spiedigitallibrary.org,Scholar\n - DOMAIN-SUFFIX,springer.com,Scholar\n - DOMAIN-SUFFIX,springerlink.com,Scholar\n - DOMAIN-SUFFIX,tandfonline.com,Scholar\n - DOMAIN-SUFFIX,un.org,Scholar\n - DOMAIN-SUFFIX,uni-bielefeld.de,Scholar\n - DOMAIN-SUFFIX,webofknowledge.com,Scholar\n - DOMAIN-SUFFIX,westlaw.com,Scholar\n - DOMAIN-SUFFIX,wiley.com,Scholar\n - DOMAIN-SUFFIX,worldbank.org,Scholar\n - DOMAIN-SUFFIX,worldscientific.com,Scholar\n - DOMAIN-SUFFIX,a.ckm.iqiyi.com,AdBlock\n - DOMAIN-SUFFIX,ad.m.iqiyi.com,AdBlock\n - DOMAIN-SUFFIX,afp.iqiyi.com,AdBlock\n - DOMAIN-SUFFIX,androidgo.duapp.com,AdBlock\n - DOMAIN-SUFFIX,api.cupid.iqiyi.com,AdBlock\n - DOMAIN-SUFFIX,api.cupid.qiyi.com,AdBlock\n - DOMAIN-SUFFIX,c.uaa.iqiyi.com,AdBlock\n - DOMAIN-SUFFIX,cloudpush.iqiyi.com,AdBlock\n - DOMAIN-SUFFIX,cm.passport.iqiyi.com,AdBlock\n - DOMAIN-SUFFIX,count.game.pps.tv,AdBlock\n - DOMAIN-SUFFIX,cupid.iqiyi.com,AdBlock\n - DOMAIN-SUFFIX,emoticon.sns.iqiyi.com,AdBlock\n - DOMAIN-SUFFIX,game.pps.tv,AdBlock\n - DOMAIN-SUFFIX,gamecenter.iqiyi.com,AdBlock\n - DOMAIN-SUFFIX,ifacelog.iqiyi.com,AdBlock\n - DOMAIN-SUFFIX,mbdlog.iqiyi.com,AdBlock\n - DOMAIN-SUFFIX,msg.71.am,AdBlock\n - DOMAIN-SUFFIX,msg.qy.net,AdBlock\n - DOMAIN-SUFFIX,msg.iqiyi.com,AdBlock\n - DOMAIN-SUFFIX,msg.video.qiyi.com,AdBlock\n - DOMAIN-SUFFIX,msg2.video.qiyi.com,AdBlock\n - DOMAIN-SUFFIX,msga.71.am,AdBlock\n - DOMAIN-SUFFIX,msga.cupid.iqiyi.com,AdBlock\n - DOMAIN-SUFFIX,nl.notice.iqiyi.com,AdBlock\n - DOMAIN-SUFFIX,nl.rcd.iqiyi.com,AdBlock\n - DOMAIN-SUFFIX,notice.iqiyi.com,AdBlock\n - DOMAIN-SUFFIX,noxagile.duapp.com,AdBlock\n - DOMAIN-SUFFIX,paopao.iqiyi.com,AdBlock\n - DOMAIN-SUFFIX,policy.video.iqiyi.com,AdBlock\n - DOMAIN-SUFFIX,static.g.iqiyi.com,AdBlock\n - DOMAIN-SUFFIX,static.g.ppstream.com,AdBlock\n - DOMAIN-SUFFIX,store.iqiyi.com,AdBlock\n - DOMAIN-SUFFIX,t7z.cupid.iqiyi.com,AdBlock\n - DOMAIN-SUFFIX,tracker.sns.iqiyi.com,AdBlock\n - DOMAIN-SUFFIX,yuedu.iqiyi.com,AdBlock\n - IP-CIDR,101.227.97.240/32,AdBlock,no-resolve\n - IP-CIDR,101.227.200.11/32,AdBlock,no-resolve\n - IP-CIDR,101.227.200.28/32,AdBlock,no-resolve\n - IP-CIDR,124.192.153.42/32,AdBlock,no-resolve\n - DOMAIN-SUFFIX,actives.youku.com,AdBlock\n - DOMAIN-SUFFIX,ad.api.3g.tudou.com,AdBlock\n - DOMAIN-SUFFIX,ad.api.3g.youku.com,AdBlock\n - DOMAIN-SUFFIX,ad.api.mobile.youku.com,AdBlock\n - DOMAIN-SUFFIX,ad.mobile.youku.com,AdBlock\n - DOMAIN-SUFFIX,a-dxk.play.api.3g.youku.com,AdBlock\n - DOMAIN-SUFFIX,b.smartvideo.youku.com,AdBlock\n - DOMAIN-SUFFIX,c.yes.youku.com,AdBlock\n - DOMAIN-SUFFIX,das.api.youku.com,AdBlock\n - DOMAIN-SUFFIX,das.mobile.youku.com,AdBlock\n - DOMAIN-SUFFIX,dev-push.m.youku.com,AdBlock\n - DOMAIN-SUFFIX,dl.g.youku.com,AdBlock\n - DOMAIN-SUFFIX,dmapp.youku.com,AdBlock\n - DOMAIN-SUFFIX,gamex.mobile.youku.com,AdBlock\n - DOMAIN-SUFFIX,hudong.pl.youku.com,AdBlock\n - DOMAIN-SUFFIX,huodong.pl.youku.com,AdBlock\n - DOMAIN-SUFFIX,huodong.vip.youku.com,AdBlock\n - DOMAIN-SUFFIX,hz.youku.com,AdBlock\n - DOMAIN-SUFFIX,iyes.youku.com,AdBlock\n - DOMAIN-SUFFIX,l.ykimg.com,AdBlock\n - DOMAIN-SUFFIX,lstat.youku.com,AdBlock\n - DOMAIN-SUFFIX,m.yes.youku.com,AdBlock\n - DOMAIN-SUFFIX,mobilemsg.youku.com,AdBlock\n - DOMAIN-SUFFIX,msg.youku.com,AdBlock\n - DOMAIN-SUFFIX,myes.youku.com,AdBlock\n - DOMAIN-SUFFIX,p.l.youku.com,AdBlock\n - DOMAIN-SUFFIX,passport-log.youku.com,AdBlock\n - DOMAIN-SUFFIX,p-log.ykimg.com,AdBlock\n - DOMAIN-SUFFIX,push.m.youku.com,AdBlock\n - DOMAIN-SUFFIX,r.l.youku.com,AdBlock\n - DOMAIN-SUFFIX,s.p.youku.com,AdBlock\n - DOMAIN-SUFFIX,sdk.api.gamex.mobile.youku.com,AdBlock\n - DOMAIN-SUFFIX,sdk.m.youku.com,AdBlock\n - DOMAIN-SUFFIX,stat.youku.com,AdBlock\n - DOMAIN-SUFFIX,store.tv.api.3g.youku.com,AdBlock\n - DOMAIN-SUFFIX,store.xl.api.3g.youku.com,AdBlock\n - DOMAIN-SUFFIX,tdrec.youku.com,AdBlock\n - DOMAIN-SUFFIX,test.ott.youku.com,AdBlock\n - DOMAIN-SUFFIX,urchin.lstat.youku.com,AdBlock\n - DOMAIN-SUFFIX,v.l.youku.com,AdBlock\n - DOMAIN-SUFFIX,val.api.youku.com,AdBlock\n - DOMAIN-SUFFIX,wan.youku.com,AdBlock\n - DOMAIN-SUFFIX,ykatr.youku.com,AdBlock\n - DOMAIN-SUFFIX,ykrec.youku.com,AdBlock\n - IP-CIDR,117.177.248.17/32,AdBlock,no-resolve\n - IP-CIDR,117.177.248.41/32,AdBlock,no-resolve\n - IP-CIDR,223.87.176.139/32,AdBlock,no-resolve\n - IP-CIDR,223.87.176.176/32,AdBlock,no-resolve\n - IP-CIDR,223.87.177.180/32,AdBlock,no-resolve\n - IP-CIDR,223.87.177.182/32,AdBlock,no-resolve\n - IP-CIDR,223.87.177.184/32,AdBlock,no-resolve\n - IP-CIDR,223.87.177.43/32,AdBlock,no-resolve\n - IP-CIDR,223.87.177.47/32,AdBlock,no-resolve\n - IP-CIDR,223.87.177.80/32,AdBlock,no-resolve\n - IP-CIDR,223.87.182.101/32,AdBlock,no-resolve\n - IP-CIDR,223.87.182.102/32,AdBlock,no-resolve\n - IP-CIDR,223.87.182.11/32,AdBlock,no-resolve\n - IP-CIDR,223.87.182.52/32,AdBlock,no-resolve\n - DOMAIN-SUFFIX,ads-api.videojj.com,AdBlock\n - DOMAIN-SUFFIX,cdn.cmop.mgtv.com,AdBlock\n - DOMAIN-SUFFIX,click.hunantv.com,AdBlock\n - DOMAIN-SUFFIX,cmop.mgtv.com,AdBlock\n - DOMAIN-SUFFIX,cytron.videojj.com,AdBlock\n - DOMAIN-SUFFIX,cytroncdn.videojj.com,AdBlock\n - DOMAIN-SUFFIX,da.hunantv.com,AdBlock\n - DOMAIN-SUFFIX,da.mgtv.com,AdBlock\n - DOMAIN-SUFFIX,imgaliyun.da.mgtv.com,AdBlock\n - DOMAIN-SUFFIX,imgaliyun.res.mgtv.com,AdBlock\n - DOMAIN-SUFFIX,m2.da.mgtv.com,AdBlock\n - DOMAIN-SUFFIX,me.videojj.com,AdBlock\n - DOMAIN-SUFFIX,mobaliyun.res.mgtv.com,AdBlock\n - DOMAIN-SUFFIX,mobile.da.mgtv.com,AdBlock\n - DOMAIN-SUFFIX,mobile2.da.mgtv.com,AdBlock\n - DOMAIN-SUFFIX,mp4.res.hunantv.com,AdBlock\n - DOMAIN-SUFFIX,pc.da.mgtv.com,AdBlock\n - DOMAIN-SUFFIX,pc1.da.mgtv.com,AdBlock\n - DOMAIN-SUFFIX,pcvideoaliyun.titan.mgtv.com,AdBlock\n - DOMAIN-SUFFIX,pcvideoyd.titan.mgtv.com,AdBlock\n - DOMAIN-SUFFIX,pcweb.v1.mgtv.com,AdBlock\n - DOMAIN-SUFFIX,plat.videojj.com,AdBlock\n - DOMAIN-SUFFIX,py.da.mgtv.com,AdBlock\n - DOMAIN-SUFFIX,res.hunantv.com,AdBlock\n - DOMAIN-SUFFIX,store.videojj.com,AdBlock\n - DOMAIN-SUFFIX,v2.da.mgtv.com,AdBlock\n - DOMAIN-SUFFIX,va.videojj.com,AdBlock\n - DOMAIN-SUFFIX,web.da.mgtv.com,AdBlock\n - DOMAIN-SUFFIX,x.da.hunantv.com,AdBlock\n - DOMAIN-SUFFIX,x.da.mgtv.com,AdBlock\n - DOMAIN-SUFFIX,x1.da.hunantv.com,AdBlock\n - DOMAIN-SUFFIX,y.da.hunantv.com,AdBlock\n - DOMAIN-SUFFIX,y.da.mgtv.com,AdBlock\n - DOMAIN-SUFFIX,1.letvlive.com,AdBlock\n - DOMAIN-SUFFIX,2.letvlive.com,AdBlock\n - DOMAIN-SUFFIX,ads1.lfengmobile.com,AdBlock\n - DOMAIN-SUFFIX,api.game.letvstore.com,AdBlock\n - DOMAIN-SUFFIX,api.push.le.com,AdBlock\n - DOMAIN-SUFFIX,ark.letv.com,AdBlock\n - DOMAIN-SUFFIX,cdn.zampdsp.com,AdBlock\n - DOMAIN-SUFFIX,cm.fancyapi.com,AdBlock\n - DOMAIN-SUFFIX,cn.api.push.le.com,AdBlock\n - DOMAIN-SUFFIX,dc.letv.com,AdBlock\n - DOMAIN-SUFFIX,fz.letv.com,AdBlock\n - DOMAIN-SUFFIX,g3.letv.com,AdBlock\n - DOMAIN-SUFFIX,minisite.letv.com,AdBlock\n - DOMAIN-SUFFIX,msg.m.letv.com,AdBlock\n - DOMAIN-SUFFIX,n.mark.letv.com,AdBlock\n - DOMAIN-SUFFIX,pro.hoye.letv.com,AdBlock\n - DOMAIN-SUFFIX,pro.letv.com,AdBlock\n - DOMAIN-SUFFIX,s.zampdsp.com,AdBlock\n - DOMAIN-SUFFIX,stat.letv.com,AdBlock\n - DOMAIN-SUFFIX,static.app.m.letv.com,AdBlock\n - DOMAIN-SUFFIX,webp2p.letv.com,AdBlock\n - DOMAIN-SUFFIX,zamplus.com,AdBlock\n - DOMAIN-SUFFIX,azabu-u.ac.jp,AdBlock\n - DOMAIN-SUFFIX,couchcoaster.jp,AdBlock\n - DOMAIN-SUFFIX,delivery.dmkt-sp.jp,AdBlock\n - DOMAIN-SUFFIX,ehg-youtube.hitbox.com,AdBlock\n - DOMAIN-SUFFIX,m-78.jp,AdBlock\n - DOMAIN-SUFFIX,nichibenren.or.jp,AdBlock\n - DOMAIN-SUFFIX,nicorette.co.kr,AdBlock\n - DOMAIN-SUFFIX,adnet.sohu.com,AdBlock\n - DOMAIN-SUFFIX,aty.sohu.com,AdBlock\n - DOMAIN-SUFFIX,epro.sogou.com,AdBlock\n - DOMAIN-SUFFIX,go.sohu.com,AdBlock\n - DOMAIN-SUFFIX,golden1.sogou.com,AdBlock\n - DOMAIN-SUFFIX,imp.optaim.com,AdBlock\n - DOMAIN-SUFFIX,inte.sogou.com,AdBlock\n - DOMAIN-SUFFIX,inte.sogoucdn.com,AdBlock\n - DOMAIN-SUFFIX,lu.sogoucdn.com,AdBlock\n - DOMAIN-SUFFIX,theta.sogoucdn.com,AdBlock\n - DOMAIN-SUFFIX,uranus.sogou.com,AdBlock\n - DOMAIN-SUFFIX,afp.pplive.com,AdBlock\n - DOMAIN-SUFFIX,app.aplus.pptv.com,AdBlock\n - DOMAIN-SUFFIX,as.aplus.pptv.com,AdBlock\n - DOMAIN-SUFFIX,asimgs.pplive.cn,AdBlock\n - DOMAIN-SUFFIX,de.as.pptv.com,AdBlock\n - DOMAIN-SUFFIX,jp.as.pptv.com,AdBlock\n - DOMAIN-SUFFIX,pp2.pptv.com,AdBlock\n - DOMAIN-SUFFIX,stat.pptv.com,AdBlock\n - DOMAIN-SUFFIX,static.g.pptv.com,AdBlock\n - DOMAIN-SUFFIX,deliver.ifeng.com,AdBlock\n - DOMAIN-SUFFIX,hxjs.tool.hexun.com,AdBlock\n - DOMAIN-SUFFIX,hxsame.hexun.com,AdBlock\n - DOMAIN-SUFFIX,itv.hexun.com,AdBlock\n - DOMAIN-SUFFIX,utrack.hexun.com,AdBlock\n - DOMAIN-SUFFIX,ad.cmvideo.cn,AdBlock\n - DOMAIN-SUFFIX,atm.cp31.ott.cibntv.net,AdBlock\n - DOMAIN-SUFFIX,aty.cp45.ott.cibntv.net,AdBlock\n - DOMAIN-SUFFIX,cpm.cm.kankan.com,AdBlock\n - DOMAIN-SUFFIX,float.kankan.com,AdBlock\n - DOMAIN-SUFFIX,houyi.baofeng.net,AdBlock\n - DOMAIN-SUFFIX,iadctest.qwapi.com,AdBlock\n - DOMAIN-SUFFIX,ad.video.51togic.com,AdBlock\n - DOMAIN-SUFFIX,biz5.kankan.com,AdBlock\n - DOMAIN-SUFFIX,c.algovid.com,AdBlock\n - DOMAIN-SUFFIX,cms.laifeng.com,AdBlock\n - DOMAIN-SUFFIX,da.mmarket.com,AdBlock\n - DOMAIN-SUFFIX,dotcounter.douyutv.com,AdBlock\n - DOMAIN-SUFFIX,g.uusee.com,AdBlock\n - DOMAIN-SUFFIX,gcdn.2mdn.net,AdBlock\n - DOMAIN-SUFFIX,gentags.net,AdBlock\n - DOMAIN-SUFFIX,gg.jtertp.com,AdBlock\n - DOMAIN-SUFFIX,gug.ku6cdn.com,AdBlock\n - DOMAIN-SUFFIX,hp.smiler-ad.com,AdBlock\n - DOMAIN-SUFFIX,kooyum.com,AdBlock\n - DOMAIN-SUFFIX,ld.kuaigames.com,AdBlock\n - DOMAIN-SUFFIX,logstat.t.sfht.com,AdBlock\n - DOMAIN-SUFFIX,match.rtbidder.net,AdBlock\n - DOMAIN-SUFFIX,mixer.cupid.ptqy.gitv.tv,AdBlock\n - DOMAIN-SUFFIX,msg.c002.ottcn.com,AdBlock\n - DOMAIN-SUFFIX,msga.ptqy.gitv.tv,AdBlock\n - DOMAIN-SUFFIX,njwxh.com,AdBlock\n - DOMAIN-SUFFIX,nl.rcd.ptqy.gitv.tv,AdBlock\n - DOMAIN-SUFFIX,n-st.vip.com,AdBlock\n - DOMAIN-SUFFIX,pb.bi.gitv.tv,AdBlock\n - DOMAIN-SUFFIX,pop.uusee.com,AdBlock\n - DOMAIN-SUFFIX,rd.kuaigames.com,AdBlock\n - DOMAIN-SUFFIX,shizen-no-megumi.com,AdBlock\n - DOMAIN-SUFFIX,shrek.6.cn,AdBlock\n - DOMAIN-SUFFIX,simba.6.cn,AdBlock\n - DOMAIN-SUFFIX,st.vq.ku6.cn,AdBlock\n - DOMAIN-SUFFIX,statcounter.com,AdBlock\n - DOMAIN-SUFFIX,static.duoshuo.com,AdBlock\n - DOMAIN-SUFFIX,static.ku6.com,AdBlock\n - DOMAIN-SUFFIX,static8.pmadx.com,AdBlock\n - DOMAIN-SUFFIX,store.ptqy.gitv.tv,AdBlock\n - DOMAIN-SUFFIX,t7z.cupid.ptqy.gitv.tv,AdBlock\n - DOMAIN-SUFFIX,traffic.uusee.com,AdBlock\n - DOMAIN-SUFFIX,union.6.cn,AdBlock\n - DOMAIN-SUFFIX,wa.gtimg.com,AdBlock\n - DOMAIN-SUFFIX,bfshan.cn,AdBlock\n - DOMAIN-SUFFIX,0.r.msn.com,AdBlock\n - DOMAIN-SUFFIX,000dn.com,AdBlock\n - DOMAIN-SUFFIX,001union.com,AdBlock\n - DOMAIN-SUFFIX,0086555.com,AdBlock\n - DOMAIN-SUFFIX,00880808.com,AdBlock\n - DOMAIN-SUFFIX,00oo00.com,AdBlock\n - DOMAIN-SUFFIX,01.gxso.net,AdBlock\n - DOMAIN-SUFFIX,010teacher.com,AdBlock\n - DOMAIN-SUFFIX,010xk.com,AdBlock\n - DOMAIN-SUFFIX,018520.com,AdBlock\n - DOMAIN-SUFFIX,01daa.lubih.com,AdBlock\n - DOMAIN-SUFFIX,01daa.lutci.com,AdBlock\n - DOMAIN-SUFFIX,01daa.lutgh.com,AdBlock\n - DOMAIN-SUFFIX,01daa.luvbr.com,AdBlock\n - DOMAIN-SUFFIX,01daa.luytr.com,AdBlock\n - DOMAIN-SUFFIX,022aifang.com,AdBlock\n - DOMAIN-SUFFIX,023hysj.com,AdBlock\n - DOMAIN-SUFFIX,025suyu.com,AdBlock\n - DOMAIN-SUFFIX,0313413.com,AdBlock\n - DOMAIN-SUFFIX,0451106.com,AdBlock\n - DOMAIN-SUFFIX,0531kt.com,AdBlock\n - DOMAIN-SUFFIX,0592weixin.com,AdBlock\n - DOMAIN-SUFFIX,0594003.com,AdBlock\n - DOMAIN-SUFFIX,06362.com,AdBlock\n - DOMAIN-SUFFIX,0756sjlm.com.cn,AdBlock\n - DOMAIN-SUFFIX,09_19.supfree.net,AdBlock\n - DOMAIN-SUFFIX,0aqpqdju.me,AdBlock\n - DOMAIN-SUFFIX,0x01e7.website,AdBlock\n - DOMAIN-SUFFIX,0xxd.com,AdBlock\n - DOMAIN-SUFFIX,1.1010pic.com,AdBlock\n - DOMAIN-SUFFIX,1.201980.com,AdBlock\n - DOMAIN-SUFFIX,1.21shebao.com,AdBlock\n - DOMAIN-SUFFIX,1.51sxue.cn,AdBlock\n - DOMAIN-SUFFIX,1.aili.com,AdBlock\n - DOMAIN-SUFFIX,1.bashenghuo.com,AdBlock\n - DOMAIN-SUFFIX,1.chcx.cn,AdBlock\n - DOMAIN-SUFFIX,1.cjcp.cn,AdBlock\n - DOMAIN-SUFFIX,1.codesdq.com,AdBlock\n - DOMAIN-SUFFIX,1.feihua.com,AdBlock\n - DOMAIN-SUFFIX,1.glook.cn,AdBlock\n - DOMAIN-SUFFIX,1.hao123.com,AdBlock\n - DOMAIN-SUFFIX,1.hnyouneng.com,AdBlock\n - DOMAIN-SUFFIX,1.hslyqs.com,AdBlock\n - DOMAIN-SUFFIX,1.i1766.com,AdBlock\n - DOMAIN-SUFFIX,1.iqeq.com.cn,AdBlock\n - DOMAIN-SUFFIX,1.jeasyui.net,AdBlock\n - DOMAIN-SUFFIX,1.mgff.com,AdBlock\n - DOMAIN-SUFFIX,1.nanrenwo.net,AdBlock\n - DOMAIN-SUFFIX,1.panduoduo.net,AdBlock\n - DOMAIN-SUFFIX,1.qtmojo.cn,AdBlock\n - DOMAIN-SUFFIX,1.rengshu.com,AdBlock\n - DOMAIN-SUFFIX,1.soufy.cn,AdBlock\n - DOMAIN-SUFFIX,1.tulaoshi.com,AdBlock\n - DOMAIN-SUFFIX,1.tuxi.com.cn,AdBlock\n - DOMAIN-SUFFIX,1.win7china.com,AdBlock\n - DOMAIN-SUFFIX,1.win7sky.com,AdBlock\n - DOMAIN-SUFFIX,1.wps.cn,AdBlock\n - DOMAIN-SUFFIX,1.xiaopin5.com,AdBlock\n - DOMAIN-SUFFIX,1.xiaozhizhijia.com,AdBlock\n - DOMAIN-SUFFIX,1.xilu.com,AdBlock\n - DOMAIN-SUFFIX,1.zw3e.com,AdBlock\n - DOMAIN-SUFFIX,1000dy.com,AdBlock\n - DOMAIN-SUFFIX,10086.cn.baidu.cdn.yiwk.com,AdBlock\n - DOMAIN-SUFFIX,100fenlm.com,AdBlock\n - DOMAIN-SUFFIX,1017.cn,AdBlock\n - DOMAIN-SUFFIX,10up.com,AdBlock\n - DOMAIN-SUFFIX,11.hydcd.com,AdBlock\n - DOMAIN-SUFFIX,111111qb.com,AdBlock\n - DOMAIN-SUFFIX,111cn.net,AdBlock\n - DOMAIN-SUFFIX,1133.cc,AdBlock\n - DOMAIN-SUFFIX,114la.com,AdBlock\n - DOMAIN-SUFFIX,1178.shucong.com,AdBlock\n - DOMAIN-SUFFIX,11g.yiqig.cn,AdBlock\n - DOMAIN-SUFFIX,1224.dxsbb.com,AdBlock\n - DOMAIN-SUFFIX,123.sogou.com,AdBlock\n - DOMAIN-SUFFIX,12306media.com,AdBlock\n - DOMAIN-SUFFIX,1234xm.com,AdBlock\n - DOMAIN-SUFFIX,12365chia.com,AdBlock\n - DOMAIN-SUFFIX,123hala.com,AdBlock\n - DOMAIN-SUFFIX,123juzi.net,AdBlock\n - DOMAIN-SUFFIX,13023.url.7wkw.com,AdBlock\n - DOMAIN-SUFFIX,138138138.top,AdBlock\n - DOMAIN-SUFFIX,142904.com,AdBlock\n - DOMAIN-SUFFIX,144.dragonparking.com,AdBlock\n - DOMAIN-SUFFIX,1495039.com,AdBlock\n - DOMAIN-SUFFIX,163.wrating.com,AdBlock\n - DOMAIN-SUFFIX,163ren.com,AdBlock\n - DOMAIN-SUFFIX,168.it168.com,AdBlock\n - DOMAIN-SUFFIX,1680go.com,AdBlock\n - DOMAIN-SUFFIX,168ad.cc,AdBlock\n - DOMAIN-SUFFIX,170yy.com,AdBlock\n - DOMAIN-SUFFIX,175bar.com,AdBlock\n - DOMAIN-SUFFIX,176um.com,AdBlock\n - DOMAIN-SUFFIX,178gg.com,AdBlock\n - DOMAIN-SUFFIX,17gouwuba.com,AdBlock\n - DOMAIN-SUFFIX,17leyi.com,AdBlock\n - DOMAIN-SUFFIX,17un.co,AdBlock\n - DOMAIN-SUFFIX,17un.com,AdBlock\n - DOMAIN-SUFFIX,17zhaole.com,AdBlock\n - DOMAIN-SUFFIX,189zj.cn,AdBlock\n - DOMAIN-SUFFIX,18av.mm-cg.co,AdBlock\n - DOMAIN-SUFFIX,18dusun.com,AdBlock\n - DOMAIN-SUFFIX,18tzx.com,AdBlock\n - DOMAIN-SUFFIX,1933000.com,AdBlock\n - DOMAIN-SUFFIX,1d1px.net,AdBlock\n - DOMAIN-SUFFIX,1e2hyl3b.wq42211.com,AdBlock\n - DOMAIN-SUFFIX,1i580.com,AdBlock\n - DOMAIN-SUFFIX,1kmb.cn,AdBlock\n - DOMAIN-SUFFIX,1kxun.mobi,AdBlock\n - DOMAIN-SUFFIX,1kzh.com,AdBlock\n - DOMAIN-SUFFIX,1l1.cc,AdBlock\n - DOMAIN-SUFFIX,1lib.cn,AdBlock\n - DOMAIN-SUFFIX,1o26.com,AdBlock\n - DOMAIN-SUFFIX,1qwe3r.com,AdBlock\n - DOMAIN-SUFFIX,1tlm.cn,AdBlock\n - DOMAIN-SUFFIX,1uandun.com,AdBlock\n - DOMAIN-SUFFIX,1x3x.com,AdBlock\n - DOMAIN-SUFFIX,2.1010pic.com,AdBlock\n - DOMAIN-SUFFIX,2.21shebao.com,AdBlock\n - DOMAIN-SUFFIX,2.5aigushi.com,AdBlock\n - DOMAIN-SUFFIX,2.aili.com,AdBlock\n - DOMAIN-SUFFIX,2.bashenghuo.com,AdBlock\n - DOMAIN-SUFFIX,2.heiyange.com,AdBlock\n - DOMAIN-SUFFIX,2.mobixs.cn,AdBlock\n - DOMAIN-SUFFIX,2.nanrenwo.net,AdBlock\n - DOMAIN-SUFFIX,2.rengshu.com,AdBlock\n - DOMAIN-SUFFIX,2.tuxi.com.cn,AdBlock\n - DOMAIN-SUFFIX,201071.com,AdBlock\n - DOMAIN-SUFFIX,2012.8684.com,AdBlock\n - DOMAIN-SUFFIX,2012ui.com,AdBlock\n - DOMAIN-SUFFIX,20150930.cf,AdBlock\n - DOMAIN-SUFFIX,2016.sina.cn,AdBlock\n - DOMAIN-SUFFIX,2016bobo.cf,AdBlock\n - DOMAIN-SUFFIX,2017img.myxh999.com,AdBlock\n - DOMAIN-SUFFIX,202m.com,AdBlock\n - DOMAIN-SUFFIX,203710.com,AdBlock\n - DOMAIN-SUFFIX,2144.cn,AdBlock\n - DOMAIN-SUFFIX,21union.com,AdBlock\n - DOMAIN-SUFFIX,22.qingsongbar.com,AdBlock\n - DOMAIN-SUFFIX,22222jsc.com,AdBlock\n - DOMAIN-SUFFIX,222627.com,AdBlock\n - DOMAIN-SUFFIX,22lm.cc,AdBlock\n - DOMAIN-SUFFIX,233wo.com,AdBlock\n - DOMAIN-SUFFIX,2345.cn,AdBlock\n - DOMAIN-SUFFIX,2345api.dftoutiao.com,AdBlock\n - DOMAIN-SUFFIX,2345apicode.dftoutiao.com,AdBlock\n - DOMAIN-SUFFIX,2345at.com,AdBlock\n - DOMAIN-SUFFIX,235123.net,AdBlock\n - DOMAIN-SUFFIX,24haitao.net,AdBlock\n - DOMAIN-SUFFIX,256ppp.com,AdBlock\n - DOMAIN-SUFFIX,268mob.cn,AdBlock\n - DOMAIN-SUFFIX,272829.cc,AdBlock\n - DOMAIN-SUFFIX,272xb.com,AdBlock\n - DOMAIN-SUFFIX,285680.com,AdBlock\n - DOMAIN-SUFFIX,28acglz.com,AdBlock\n - DOMAIN-SUFFIX,2a.com.cn,AdBlock\n - DOMAIN-SUFFIX,2cnt.net,AdBlock\n - DOMAIN-SUFFIX,2m2n.com,AdBlock\n - DOMAIN-SUFFIX,2o7.net,AdBlock\n - DOMAIN-SUFFIX,3.guidaye.com,AdBlock\n - DOMAIN-SUFFIX,3.ssqzj.com,AdBlock\n - DOMAIN-SUFFIX,30350f.com,AdBlock\n - DOMAIN-SUFFIX,30407799.com,AdBlock\n - DOMAIN-SUFFIX,30ampj.com,AdBlock\n - DOMAIN-SUFFIX,31.media.tumblr.com,AdBlock\n - DOMAIN-SUFFIX,312036.com,AdBlock\n - DOMAIN-SUFFIX,3180555.com,AdBlock\n - DOMAIN-SUFFIX,32414.com,AdBlock\n - DOMAIN-SUFFIX,32666099.com,AdBlock\n - DOMAIN-SUFFIX,33.pcpop.com,AdBlock\n - DOMAIN-SUFFIX,33544444.com,AdBlock\n - DOMAIN-SUFFIX,336.com,AdBlock\n - DOMAIN-SUFFIX,3388pjdc.com,AdBlock\n - DOMAIN-SUFFIX,339.cn,AdBlock\n - DOMAIN-SUFFIX,3393.com,AdBlock\n - DOMAIN-SUFFIX,33lm.cc,AdBlock\n - DOMAIN-SUFFIX,33shangyou.com,AdBlock\n - DOMAIN-SUFFIX,35baba.cn,AdBlock\n - DOMAIN-SUFFIX,3600.com,AdBlock\n - DOMAIN-SUFFIX,360640.com,AdBlock\n - DOMAIN-SUFFIX,360baidus.com,AdBlock\n - DOMAIN-SUFFIX,360jiaquan.com,AdBlock\n - DOMAIN-SUFFIX,360safego.com,AdBlock\n - DOMAIN-SUFFIX,360shopping.com.cn,AdBlock\n - DOMAIN-SUFFIX,360vip.front99.com,AdBlock\n - DOMAIN-SUFFIX,361315.cc,AdBlock\n - DOMAIN-SUFFIX,365bibi.com,AdBlock\n - DOMAIN-SUFFIX,365safego.com,AdBlock\n - DOMAIN-SUFFIX,366safego.com,AdBlock\n - DOMAIN-SUFFIX,36pn.com,AdBlock\n - DOMAIN-SUFFIX,3721zh.com,AdBlock\n - DOMAIN-SUFFIX,376zf.com,AdBlock\n - DOMAIN-SUFFIX,37cs.com,AdBlock\n - DOMAIN-SUFFIX,37mnm.com,AdBlock\n - DOMAIN-SUFFIX,37pk49.com,AdBlock\n - DOMAIN-SUFFIX,37see.com,AdBlock\n - DOMAIN-SUFFIX,37wan.cn,AdBlock\n - DOMAIN-SUFFIX,37wan.com,AdBlock\n - DOMAIN-SUFFIX,3808010.com,AdBlock\n - DOMAIN-SUFFIX,38330.bet,AdBlock\n - DOMAIN-SUFFIX,3839168.com,AdBlock\n - DOMAIN-SUFFIX,38499.com,AdBlock\n - DOMAIN-SUFFIX,38c99.com,AdBlock\n - DOMAIN-SUFFIX,39330.bet,AdBlock\n - DOMAIN-SUFFIX,3975lm.com,AdBlock\n - DOMAIN-SUFFIX,39xc.net,AdBlock\n - DOMAIN-SUFFIX,3dm.huya.com,AdBlock\n - DOMAIN-SUFFIX,3dns-2.adobe.com,AdBlock\n - DOMAIN-SUFFIX,3dns-3.adobe.com,AdBlock\n - DOMAIN-SUFFIX,3dwwwgame.com,AdBlock\n - DOMAIN-SUFFIX,3g.990.net,AdBlock\n - DOMAIN-SUFFIX,3gmimo.com,AdBlock\n - DOMAIN-SUFFIX,3gmtr.com,AdBlock\n - DOMAIN-SUFFIX,3htai.com,AdBlock\n - DOMAIN-SUFFIX,3qmh.com,AdBlock\n - DOMAIN-SUFFIX,3rd.t.sohu.com,AdBlock\n - DOMAIN-SUFFIX,3wz6z.bchuangpi.cn,AdBlock\n - DOMAIN-SUFFIX,3ygww.com,AdBlock\n - DOMAIN-SUFFIX,4009997658.com,AdBlock\n - DOMAIN-SUFFIX,404.safedog.cn,AdBlock\n - DOMAIN-SUFFIX,4207008.com,AdBlock\n - DOMAIN-SUFFIX,4242jj.com,AdBlock\n - DOMAIN-SUFFIX,4242lll.com,AdBlock\n - DOMAIN-SUFFIX,4242uuu.com,AdBlock\n - DOMAIN-SUFFIX,4336wang.cn,AdBlock\n - DOMAIN-SUFFIX,456juhd.com,AdBlock\n - DOMAIN-SUFFIX,46sg.com,AdBlock\n - DOMAIN-SUFFIX,49wanwan.com,AdBlock\n - DOMAIN-SUFFIX,4ggww.com,AdBlock\n - DOMAIN-SUFFIX,4paradigm.com,AdBlock\n - DOMAIN-SUFFIX,4wad.com,AdBlock\n - DOMAIN-SUFFIX,4xhyr.shuimujinggong.com,AdBlock\n - DOMAIN-SUFFIX,504pk.com,AdBlock\n - DOMAIN-SUFFIX,5066.net,AdBlock\n - DOMAIN-SUFFIX,50bang.org,AdBlock\n - DOMAIN-SUFFIX,51.la,AdBlock\n - DOMAIN-SUFFIX,5125129.com,AdBlock\n - DOMAIN-SUFFIX,513hch.com,AdBlock\n - DOMAIN-SUFFIX,517m.cn,AdBlock\n - DOMAIN-SUFFIX,518.sdinfo.net,AdBlock\n - DOMAIN-SUFFIX,5188yy.com,AdBlock\n - DOMAIN-SUFFIX,519397.com,AdBlock\n - DOMAIN-SUFFIX,51ads.com,AdBlock\n - DOMAIN-SUFFIX,51chumoping.com,AdBlock\n - DOMAIN-SUFFIX,51dql.com,AdBlock\n - DOMAIN-SUFFIX,51gxqm.com,AdBlock\n - DOMAIN-SUFFIX,51jumintong.com,AdBlock\n - DOMAIN-SUFFIX,51la.net,AdBlock\n - DOMAIN-SUFFIX,51link.com,AdBlock\n - DOMAIN-SUFFIX,51mld.cn,AdBlock\n - DOMAIN-SUFFIX,51network.com,AdBlock\n - DOMAIN-SUFFIX,51vipedu.com,AdBlock\n - DOMAIN-SUFFIX,51weidashi.com,AdBlock\n - DOMAIN-SUFFIX,51xumei.com,AdBlock\n - DOMAIN-SUFFIX,51yes.com,AdBlock\n - DOMAIN-SUFFIX,51zhanzhuang.cn,AdBlock\n - DOMAIN-SUFFIX,5207470.com,AdBlock\n - DOMAIN-SUFFIX,5269120.com,AdBlock\n - DOMAIN-SUFFIX,526d.uunice.com,AdBlock\n - DOMAIN-SUFFIX,526dimg.uunice.com,AdBlock\n - DOMAIN-SUFFIX,5293.com,AdBlock\n - DOMAIN-SUFFIX,52kmh.com,AdBlock\n - DOMAIN-SUFFIX,52kmk.com,AdBlock\n - DOMAIN-SUFFIX,52lubo.cn,AdBlock\n - DOMAIN-SUFFIX,5345ll.com,AdBlock\n - DOMAIN-SUFFIX,537901.com,AdBlock\n - DOMAIN-SUFFIX,55.la,AdBlock\n - DOMAIN-SUFFIX,555p555p.com,AdBlock\n - DOMAIN-SUFFIX,559gp.com,AdBlock\n - DOMAIN-SUFFIX,55lu.com,AdBlock\n - DOMAIN-SUFFIX,5634.com,AdBlock\n - DOMAIN-SUFFIX,5675146.com,AdBlock\n - DOMAIN-SUFFIX,57.com.cn,AdBlock\n - DOMAIN-SUFFIX,57union.com,AdBlock\n - DOMAIN-SUFFIX,58.xgo.com.cn,AdBlock\n - DOMAIN-SUFFIX,5814889.com,AdBlock\n - DOMAIN-SUFFIX,5857.com,AdBlock\n - DOMAIN-SUFFIX,588yw.com,AdBlock\n - DOMAIN-SUFFIX,58lm.vip,AdBlock\n - DOMAIN-SUFFIX,58mingri.cn,AdBlock\n - DOMAIN-SUFFIX,58mingtian.cn,AdBlock\n - DOMAIN-SUFFIX,592man.com,AdBlock\n - DOMAIN-SUFFIX,5dg.me,AdBlock\n - DOMAIN-SUFFIX,5dian.org,AdBlock\n - DOMAIN-SUFFIX,5egk.com,AdBlock\n - DOMAIN-SUFFIX,5imoney.com,AdBlock\n - DOMAIN-SUFFIX,5jcom.com.cn,AdBlock\n - DOMAIN-SUFFIX,5vz3cfs0yd.me,AdBlock\n - DOMAIN-SUFFIX,5y9nfpes.52pk.com,AdBlock\n - DOMAIN-SUFFIX,5yrra.deshuangwang.cn,AdBlock\n - DOMAIN-SUFFIX,600ad.com,AdBlock\n - DOMAIN-SUFFIX,601654.com,AdBlock\n - DOMAIN-SUFFIX,60608787.com,AdBlock\n - DOMAIN-SUFFIX,626uc.com,AdBlock\n - DOMAIN-SUFFIX,644446.com,AdBlock\n - DOMAIN-SUFFIX,649558.com,AdBlock\n - DOMAIN-SUFFIX,64si.com,AdBlock\n - DOMAIN-SUFFIX,654mmm.com,AdBlock\n - DOMAIN-SUFFIX,6615338.cn,AdBlock\n - DOMAIN-SUFFIX,6666349.com,AdBlock\n - DOMAIN-SUFFIX,6669667.com,AdBlock\n - DOMAIN-SUFFIX,66992949.com,AdBlock\n - DOMAIN-SUFFIX,66san.com,AdBlock\n - DOMAIN-SUFFIX,6711.com,AdBlock\n - DOMAIN-SUFFIX,6728812.com,AdBlock\n - DOMAIN-SUFFIX,685wo.com,AdBlock\n - DOMAIN-SUFFIX,68665565.com,AdBlock\n - DOMAIN-SUFFIX,69duk.com,AdBlock\n - DOMAIN-SUFFIX,6a4cc.lubue.com,AdBlock\n - DOMAIN-SUFFIX,6a4cc.luvbq.com,AdBlock\n - DOMAIN-SUFFIX,6a4cc.luvbr.com,AdBlock\n - DOMAIN-SUFFIX,6a4cc.luytr.com,AdBlock\n - DOMAIN-SUFFIX,6boou.voluumtrk.com,AdBlock\n - DOMAIN-SUFFIX,6d63d3.com,AdBlock\n - DOMAIN-SUFFIX,6dad.com,AdBlock\n - DOMAIN-SUFFIX,6dvip.com,AdBlock\n - DOMAIN-SUFFIX,6huu.com,AdBlock\n - DOMAIN-SUFFIX,6kwan.com,AdBlock\n - DOMAIN-SUFFIX,6tsbe1zs.me,AdBlock\n - DOMAIN-SUFFIX,700900.com,AdBlock\n - DOMAIN-SUFFIX,706529.com,AdBlock\n - DOMAIN-SUFFIX,7080555.com,AdBlock\n - DOMAIN-SUFFIX,70e.com,AdBlock\n - DOMAIN-SUFFIX,70lm.com,AdBlock\n - DOMAIN-SUFFIX,711kk.com,AdBlock\n - DOMAIN-SUFFIX,716703.com,AdBlock\n - DOMAIN-SUFFIX,71sem.com,AdBlock\n - DOMAIN-SUFFIX,73.sinawap.com,AdBlock\n - DOMAIN-SUFFIX,743m1.11a12.com,AdBlock\n - DOMAIN-SUFFIX,749558.com,AdBlock\n - DOMAIN-SUFFIX,749808.com,AdBlock\n - DOMAIN-SUFFIX,7540.com,AdBlock\n - DOMAIN-SUFFIX,75to.com,AdBlock\n - DOMAIN-SUFFIX,7631.com,AdBlock\n - DOMAIN-SUFFIX,766ba.net,AdBlock\n - DOMAIN-SUFFIX,76802.net,AdBlock\n - DOMAIN-SUFFIX,77455.com,AdBlock\n - DOMAIN-SUFFIX,778669.com,AdBlock\n - DOMAIN-SUFFIX,7794.com,AdBlock\n - DOMAIN-SUFFIX,77power.com,AdBlock\n - DOMAIN-SUFFIX,77u.com,AdBlock\n - DOMAIN-SUFFIX,77xtv.com,AdBlock\n - DOMAIN-SUFFIX,7891655.cn,AdBlock\n - DOMAIN-SUFFIX,7car.com.cn,AdBlock\n - DOMAIN-SUFFIX,7clink.com,AdBlock\n - DOMAIN-SUFFIX,7dah8.com,AdBlock\n - DOMAIN-SUFFIX,7gg.cc,AdBlock\n - DOMAIN-SUFFIX,7jiajiao.com,AdBlock\n - DOMAIN-SUFFIX,7mad.7m.cn,AdBlock\n - DOMAIN-SUFFIX,7pk.com,AdBlock\n - DOMAIN-SUFFIX,7wen.cn,AdBlock\n - DOMAIN-SUFFIX,7xz3.com,AdBlock\n - DOMAIN-SUFFIX,7z66.com,AdBlock\n - DOMAIN-SUFFIX,8.jrj.com,AdBlock\n - DOMAIN-SUFFIX,801.tianyaui.com,AdBlock\n - DOMAIN-SUFFIX,8066hg.com,AdBlock\n - DOMAIN-SUFFIX,80sjw.com,AdBlock\n - DOMAIN-SUFFIX,813690.top,AdBlock\n - DOMAIN-SUFFIX,8184.cc,AdBlock\n - DOMAIN-SUFFIX,818mov.com,AdBlock\n - DOMAIN-SUFFIX,81c.cn,AdBlock\n - DOMAIN-SUFFIX,8269996.com,AdBlock\n - DOMAIN-SUFFIX,8368661.com,AdBlock\n - DOMAIN-SUFFIX,846.move7.com,AdBlock\n - DOMAIN-SUFFIX,849558.com,AdBlock\n - DOMAIN-SUFFIX,85058s.com,AdBlock\n - DOMAIN-SUFFIX,8521448.com,AdBlock\n - DOMAIN-SUFFIX,85655095.com,AdBlock\n - DOMAIN-SUFFIX,859377.com,AdBlock\n - DOMAIN-SUFFIX,85tgw.com,AdBlock\n - DOMAIN-SUFFIX,86.cc,AdBlock\n - DOMAIN-SUFFIX,860010.com,AdBlock\n - DOMAIN-SUFFIX,86kx.com,AdBlock\n - DOMAIN-SUFFIX,878090.com,AdBlock\n - DOMAIN-SUFFIX,8800271.com.cn,AdBlock\n - DOMAIN-SUFFIX,88210212.com,AdBlock\n - DOMAIN-SUFFIX,8866786.com,AdBlock\n - DOMAIN-SUFFIX,888.izhufu.net,AdBlock\n - DOMAIN-SUFFIX,888.jiuwanwang.com,AdBlock\n - DOMAIN-SUFFIX,888.tv.sohu.com,AdBlock\n - DOMAIN-SUFFIX,88818122.cn,AdBlock\n - DOMAIN-SUFFIX,888zr022.com,AdBlock\n - DOMAIN-SUFFIX,88cncc.com,AdBlock\n - DOMAIN-SUFFIX,88rpg.net,AdBlock\n - DOMAIN-SUFFIX,88shu.cn,AdBlock\n - DOMAIN-SUFFIX,892155.com,AdBlock\n - DOMAIN-SUFFIX,89h8.com,AdBlock\n - DOMAIN-SUFFIX,8dulm.com,AdBlock\n - DOMAIN-SUFFIX,8hykthze.cricket,AdBlock\n - DOMAIN-SUFFIX,8jd2lfsq.me,AdBlock\n - DOMAIN-SUFFIX,8jkx.com,AdBlock\n - DOMAIN-SUFFIX,8le8le.com,AdBlock\n - DOMAIN-SUFFIX,8mfty.com,AdBlock\n - DOMAIN-SUFFIX,8ox.cn,AdBlock\n - DOMAIN-SUFFIX,90053999.com,AdBlock\n - DOMAIN-SUFFIX,910weixin.com,AdBlock\n - DOMAIN-SUFFIX,911.cc,AdBlock\n - DOMAIN-SUFFIX,915.com,AdBlock\n - DOMAIN-SUFFIX,91ad.bestvogue.com,AdBlock\n - DOMAIN-SUFFIX,91adv.com,AdBlock\n - DOMAIN-SUFFIX,91hui.com,AdBlock\n - DOMAIN-SUFFIX,91veg.com,AdBlock\n - DOMAIN-SUFFIX,91xry.com,AdBlock\n - DOMAIN-SUFFIX,91ysa.com,AdBlock\n - DOMAIN-SUFFIX,91zgm.com,AdBlock\n - DOMAIN-SUFFIX,92x.tumblr.com,AdBlock\n - DOMAIN-SUFFIX,930.dragonparking.com,AdBlock\n - DOMAIN-SUFFIX,93manhua.com,AdBlock\n - DOMAIN-SUFFIX,94lm.com,AdBlock\n - DOMAIN-SUFFIX,95105012.com,AdBlock\n - DOMAIN-SUFFIX,9519.net,AdBlock\n - DOMAIN-SUFFIX,95558000.com,AdBlock\n - DOMAIN-SUFFIX,9565365.com,AdBlock\n - DOMAIN-SUFFIX,9566180.com,AdBlock\n - DOMAIN-SUFFIX,96mob.com,AdBlock\n - DOMAIN-SUFFIX,9948000.com,AdBlock\n - DOMAIN-SUFFIX,99909988.com,AdBlock\n - DOMAIN-SUFFIX,99click.com,AdBlock\n - DOMAIN-SUFFIX,99ddd.com,AdBlock\n - DOMAIN-SUFFIX,99lolo.com,AdBlock\n - DOMAIN-SUFFIX,9ads.net,AdBlock\n - DOMAIN-SUFFIX,9dtiny.cn,AdBlock\n - DOMAIN-SUFFIX,9kff.com,AdBlock\n - DOMAIN-SUFFIX,9pkw.com,AdBlock\n - DOMAIN-SUFFIX,9s6q.cn,AdBlock\n - DOMAIN-SUFFIX,9tn.cc,AdBlock\n - DOMAIN-SUFFIX,9wushuo.com,AdBlock\n - DOMAIN-SUFFIX,a.198banjia.com,AdBlock\n - DOMAIN-SUFFIX,a.53yao.com,AdBlock\n - DOMAIN-SUFFIX,a.5ykj.com,AdBlock\n - DOMAIN-SUFFIX,a.80982.org,AdBlock\n - DOMAIN-SUFFIX,a.ads1.msn.com,AdBlock\n - DOMAIN-SUFFIX,a.ads2.msn.com,AdBlock\n - DOMAIN-SUFFIX,a.armystar.com,AdBlock\n - DOMAIN-SUFFIX,a.baidu.com,AdBlock\n - DOMAIN-SUFFIX,a.baiy.net,AdBlock\n - DOMAIN-SUFFIX,a.baomihua.com,AdBlock\n - DOMAIN-SUFFIX,a.beilamusi.com,AdBlock\n - DOMAIN-SUFFIX,a.benshiw.net,AdBlock\n - DOMAIN-SUFFIX,a.bshu.com,AdBlock\n - DOMAIN-SUFFIX,a.cdngeek.net,AdBlock\n - DOMAIN-SUFFIX,a.clipconverter.cc,AdBlock\n - DOMAIN-SUFFIX,a.cn.duoyi.com,AdBlock\n - DOMAIN-SUFFIX,a.dangdang.com,AdBlock\n - DOMAIN-SUFFIX,a.dianjoy.com,AdBlock\n - DOMAIN-SUFFIX,a.dounanhuahui.com,AdBlock\n - DOMAIN-SUFFIX,a.duanmeiwen.com,AdBlock\n - DOMAIN-SUFFIX,a.e7009.com,AdBlock\n - DOMAIN-SUFFIX,a.ecook.cn,AdBlock\n - DOMAIN-SUFFIX,a.epinv.com,AdBlock\n - DOMAIN-SUFFIX,a.eporner.com,AdBlock\n - DOMAIN-SUFFIX,a.exam58.com,AdBlock\n - DOMAIN-SUFFIX,a.fengyx.com,AdBlock\n - DOMAIN-SUFFIX,a.fwsir.com,AdBlock\n - DOMAIN-SUFFIX,a.giantrealm.com,AdBlock\n - DOMAIN-SUFFIX,a.global.msads.net,AdBlock\n - DOMAIN-SUFFIX,a.hl.mi.com,AdBlock\n - DOMAIN-SUFFIX,a.holagames.com,AdBlock\n - DOMAIN-SUFFIX,a.irs01.com,AdBlock\n - DOMAIN-SUFFIX,a.itiexue.net,AdBlock\n - DOMAIN-SUFFIX,a.jyeoo.com,AdBlock\n - DOMAIN-SUFFIX,a.kandiaoyu.com,AdBlock\n - DOMAIN-SUFFIX,a.kejixun.com,AdBlock\n - DOMAIN-SUFFIX,a.kickass.to,AdBlock\n - DOMAIN-SUFFIX,a.koudai.com,AdBlock\n - DOMAIN-SUFFIX,a.livesportmedia.eu,AdBlock\n - DOMAIN-SUFFIX,a.lolwot.com,AdBlock\n - DOMAIN-SUFFIX,a.ltdnc.com,AdBlock\n - DOMAIN-SUFFIX,a.lwinl.com,AdBlock\n - DOMAIN-SUFFIX,a.lz13.cn,AdBlock\n - DOMAIN-SUFFIX,a.m.gxwztv.com,AdBlock\n - DOMAIN-SUFFIX,a.m.shuhuangge.org,AdBlock\n - DOMAIN-SUFFIX,a.mct01.com,AdBlock\n - DOMAIN-SUFFIX,a.mjlnbx.cn,AdBlock\n - DOMAIN-SUFFIX,a.nanhuwang.com,AdBlock\n - DOMAIN-SUFFIX,a.nowscore.com,AdBlock\n - DOMAIN-SUFFIX,a.qiao024.com,AdBlock\n - DOMAIN-SUFFIX,a.qinghua5.com,AdBlock\n - DOMAIN-SUFFIX,a.shangz99991.com,AdBlock\n - DOMAIN-SUFFIX,a.shczz.com,AdBlock\n - DOMAIN-SUFFIX,a.shenchuang.com,AdBlock\n - DOMAIN-SUFFIX,a.shuoshuodaquan.net,AdBlock\n - DOMAIN-SUFFIX,a.solarmovie.is,AdBlock\n - DOMAIN-SUFFIX,a.soonyou123.com,AdBlock\n - DOMAIN-SUFFIX,a.starstar19999.com,AdBlock\n - DOMAIN-SUFFIX,a.startui19999.com,AdBlock\n - DOMAIN-SUFFIX,a.thefreethoughtproject.com,AdBlock\n - DOMAIN-SUFFIX,a.tribalfusion.com,AdBlock\n - DOMAIN-SUFFIX,a.tujidao.com,AdBlock\n - DOMAIN-SUFFIX,a.tuuituii2999.com,AdBlock\n - DOMAIN-SUFFIX,a.ucoz.net,AdBlock\n - DOMAIN-SUFFIX,a.union.mi.com,AdBlock\n - DOMAIN-SUFFIX,a.visualrevenue.com,AdBlock\n - DOMAIN-SUFFIX,a.vlion.cn,AdBlock\n - DOMAIN-SUFFIX,a.waczt.cn,AdBlock\n - DOMAIN-SUFFIX,a.wlfnb.com,AdBlock\n - DOMAIN-SUFFIX,a.xinwenge.net,AdBlock\n - DOMAIN-SUFFIX,a.xixiyishu.com,AdBlock\n - DOMAIN-SUFFIX,a.xizi.com,AdBlock\n - DOMAIN-SUFFIX,a.xywy.com,AdBlock\n - DOMAIN-SUFFIX,a.yangshengtang123.com,AdBlock\n - DOMAIN-SUFFIX,a.yixie8.com,AdBlock\n - DOMAIN-SUFFIX,a.yjbys.com,AdBlock\n - DOMAIN-SUFFIX,a.youdao.com,AdBlock\n - DOMAIN-SUFFIX,a1.0s.net.cn,AdBlock\n - DOMAIN-SUFFIX,a1.azg168.cn,AdBlock\n - DOMAIN-SUFFIX,a1.gexing.me,AdBlock\n - DOMAIN-SUFFIX,a1.huanqiumil.com,AdBlock\n - DOMAIN-SUFFIX,a1.huiqituan.com,AdBlock\n - DOMAIN-SUFFIX,a1.itc.cn,AdBlock\n - DOMAIN-SUFFIX,a1.liuxue86.com,AdBlock\n - DOMAIN-SUFFIX,a1.lmaq.cn,AdBlock\n - DOMAIN-SUFFIX,a1.peoplecdn.cn,AdBlock\n - DOMAIN-SUFFIX,a1.vdolady.com,AdBlock\n - DOMAIN-SUFFIX,a1.yuuedu.com,AdBlock\n - DOMAIN-SUFFIX,a1.zhanzhang.net,AdBlock\n - DOMAIN-SUFFIX,a1click.cpc.sogou.com,AdBlock\n - DOMAIN-SUFFIX,a2.b310.com,AdBlock\n - DOMAIN-SUFFIX,a2.huanqiumil.com,AdBlock\n - DOMAIN-SUFFIX,a2.rabbitpre.com,AdBlock\n - DOMAIN-SUFFIX,a3.ikafan.com,AdBlock\n - DOMAIN-SUFFIX,a3p4.net,AdBlock\n - DOMAIN-SUFFIX,a4.b2b168.com,AdBlock\n - DOMAIN-SUFFIX,a4.ikafan.com,AdBlock\n - DOMAIN-SUFFIX,a4.yeshj.com,AdBlock\n - DOMAIN-SUFFIX,a5.yeshj.com,AdBlock\n - DOMAIN-SUFFIX,a6.bjdianyue.com,AdBlock\n - DOMAIN-SUFFIX,a6.codejumps.com,AdBlock\n - DOMAIN-SUFFIX,a6.taobanapp.com,AdBlock\n - DOMAIN-SUFFIX,a6s.1cakeclub.com,AdBlock\n - DOMAIN-SUFFIX,a6s.modoupai.com,AdBlock\n - DOMAIN-SUFFIX,a6s.ruyiqufu.com,AdBlock\n - DOMAIN-SUFFIX,a6s.ve001nz.com,AdBlock\n - DOMAIN-SUFFIX,a7shun.com,AdBlock\n - DOMAIN-SUFFIX,a907907.com,AdBlock\n - DOMAIN-SUFFIX,a9377j.com,AdBlock\n - DOMAIN-SUFFIX,aa.goodsblock.mgid.com,AdBlock\n - DOMAIN-SUFFIX,aa.jiankang.com,AdBlock\n - DOMAIN-SUFFIX,aa.tianya999.com,AdBlock\n - DOMAIN-SUFFIX,aa.xiangxiangmf.com,AdBlock\n - DOMAIN-SUFFIX,aa.zldh123.com,AdBlock\n - DOMAIN-SUFFIX,aa0.pub.funshion.com,AdBlock\n - DOMAIN-SUFFIX,aa1.pub.funshion.com,AdBlock\n - DOMAIN-SUFFIX,aafanke.cc,AdBlock\n - DOMAIN-SUFFIX,aa-gb.mgid.com,AdBlock\n - DOMAIN-SUFFIX,aam.adsremote.scrippsnetworks.com,AdBlock\n - DOMAIN-SUFFIX,ab.dydab.com,AdBlock\n - DOMAIN-SUFFIX,ab.goodsblock.mgid.com,AdBlock\n - DOMAIN-SUFFIX,ab.hysdknb.com,AdBlock\n - DOMAIN-SUFFIX,ab.meishiba.com.cn,AdBlock\n - DOMAIN-SUFFIX,ab.sc115.com,AdBlock\n - DOMAIN-SUFFIX,abbyychina.com,AdBlock\n - DOMAIN-SUFFIX,abc.dooccn.com,AdBlock\n - DOMAIN-SUFFIX,abc.douguo.com,AdBlock\n - DOMAIN-SUFFIX,abc.eastlady.cn,AdBlock\n - DOMAIN-SUFFIX,abc.hkepc.com,AdBlock\n - DOMAIN-SUFFIX,abc.ruiwen.com,AdBlock\n - DOMAIN-SUFFIX,abc.xtyx918.com,AdBlock\n - DOMAIN-SUFFIX,abc.yjbys.com,AdBlock\n - DOMAIN-SUFFIX,abc.zhiyaspa.com,AdBlock\n - DOMAIN-SUFFIX,abcd.zsrt88.cn,AdBlock\n - DOMAIN-SUFFIX,abcj.dooccn.com,AdBlock\n - DOMAIN-SUFFIX,ab-gb.mgid.com,AdBlock\n - DOMAIN-SUFFIX,abtest.mistat.xiaomi.com,AdBlock\n - DOMAIN-SUFFIX,ac.atpanel.com,AdBlock\n - DOMAIN-SUFFIX,ac2.msn.com,AdBlock\n - DOMAIN-SUFFIX,ac3.msn.com,AdBlock\n - DOMAIN-SUFFIX,acasys88.cn,AdBlock\n - DOMAIN-SUFFIX,access.njherald.com,AdBlock\n - DOMAIN-SUFFIX,ac-gb.mgid.com,AdBlock\n - DOMAIN-SUFFIX,acint.net,AdBlock\n - DOMAIN-SUFFIX,acm.dzwww.com,AdBlock\n - DOMAIN-SUFFIX,acs86.com,AdBlock\n - DOMAIN-SUFFIX,acsystem.wasu.cn,AdBlock\n - DOMAIN-SUFFIX,act2.mediafour.com,AdBlock\n - DOMAIN-SUFFIX,activate.adobe.com,AdBlock\n - DOMAIN-SUFFIX,activate.wip3.adobe.com,AdBlock\n - DOMAIN-SUFFIX,activate-sea.adobe.com,AdBlock\n - DOMAIN-SUFFIX,activate-sjc0.adobe.com,AdBlock\n - DOMAIN-SUFFIX,activation.cyberlink.com,AdBlock\n - DOMAIN-SUFFIX,activation.easeus.com,AdBlock\n - DOMAIN-SUFFIX,active.baofeng.com,AdBlock\n - DOMAIN-SUFFIX,activeqq.3g.qq.com,AdBlock\n - DOMAIN-SUFFIX,activity.serving-sys.com,AdBlock\n - DOMAIN-SUFFIX,activity.tuifish.com,AdBlock\n - DOMAIN-SUFFIX,activity.yuyiya.com,AdBlock\n - DOMAIN-SUFFIX,actlog.dftoutiao.com,AdBlock\n - DOMAIN-SUFFIX,actsdk.idreamsky.com,AdBlock\n - DOMAIN-SUFFIX,acuityplatform.com,AdBlock\n - DOMAIN-SUFFIX,acwgf.com,AdBlock\n - DOMAIN-SUFFIX,acxiom-online.com,AdBlock\n - DOMAIN-SUFFIX,ad.1111cpc.com,AdBlock\n - DOMAIN-SUFFIX,ad.12306.cn,AdBlock\n - DOMAIN-SUFFIX,ad.17173.com,AdBlock\n - DOMAIN-SUFFIX,ad.1kxun.com,AdBlock\n - DOMAIN-SUFFIX,ad.3.cn,AdBlock\n - DOMAIN-SUFFIX,ad.360yield.com,AdBlock\n - DOMAIN-SUFFIX,ad.363.in,AdBlock\n - DOMAIN-SUFFIX,ad.3dnews.ru,AdBlock\n - DOMAIN-SUFFIX,ad.51wnl.com,AdBlock\n - DOMAIN-SUFFIX,ad.95306.cn,AdBlock\n - DOMAIN-SUFFIX,ad.about.co.kr,AdBlock\n - DOMAIN-SUFFIX,ad.accessmediaproductions.com,AdBlock\n - DOMAIN-SUFFIX,ad.adhouyi.cn,AdBlock\n - DOMAIN-SUFFIX,ad.aidalan.com,AdBlock\n - DOMAIN-SUFFIX,ad.api.moji.com,AdBlock\n - DOMAIN-SUFFIX,ad.auditude.com,AdBlock\n - DOMAIN-SUFFIX,ad.bayescom.com,AdBlock\n - DOMAIN-SUFFIX,ad.beihai365.com,AdBlock\n - DOMAIN-SUFFIX,ad.bitmedia.io,AdBlock\n - DOMAIN-SUFFIX,ad.bjmama.net,AdBlock\n - DOMAIN-SUFFIX,ad.cacafly.com,AdBlock\n - DOMAIN-SUFFIX,ad.cctv.com,AdBlock\n - DOMAIN-SUFFIX,ad.cooks.com,AdBlock\n - DOMAIN-SUFFIX,ad.crichd.in,AdBlock\n - DOMAIN-SUFFIX,ad.csdn.net,AdBlock\n - DOMAIN-SUFFIX,ad.dedecms.com,AdBlock\n - DOMAIN-SUFFIX,ad.digitimes.com.tw,AdBlock\n - DOMAIN-SUFFIX,ad.directmirror.com,AdBlock\n - DOMAIN-SUFFIX,ad.dokrmob.com,AdBlock\n - DOMAIN-SUFFIX,ad.doubanio.com,AdBlock\n - DOMAIN-SUFFIX,ad.download.cnet.com,AdBlock\n - DOMAIN-SUFFIX,ad.dqwjzm.com,AdBlock\n - DOMAIN-SUFFIX,ad.duapps.com,AdBlock\n - DOMAIN-SUFFIX,ad.duga.jp,AdBlock\n - DOMAIN-SUFFIX,ad.dumedia.ru,AdBlock\n - DOMAIN-SUFFIX,ad.duomi.com,AdBlock\n - DOMAIN-SUFFIX,ad.dzwindows.com,AdBlock\n - DOMAIN-SUFFIX,ad.dzwww.com,AdBlock\n - DOMAIN-SUFFIX,ad.egou.com,AdBlock\n - DOMAIN-SUFFIX,ad.endpo.in,AdBlock\n - DOMAIN-SUFFIX,ad.epochtimes.com,AdBlock\n - DOMAIN-SUFFIX,ad.eporner.com,AdBlock\n - DOMAIN-SUFFIX,ad.evozi.com,AdBlock\n - DOMAIN-SUFFIX,ad.flipboard.com,AdBlock\n - DOMAIN-SUFFIX,ad.flurry.com,AdBlock\n - DOMAIN-SUFFIX,ad.flux.com,AdBlock\n - DOMAIN-SUFFIX,ad.fnnews.com,AdBlock\n - DOMAIN-SUFFIX,ad.foxnetworks.com,AdBlock\n - DOMAIN-SUFFIX,ad.funp.com,AdBlock\n - DOMAIN-SUFFIX,ad.funshion.org.cn,AdBlock\n - DOMAIN-SUFFIX,ad.gametower.com.tw,AdBlock\n - DOMAIN-SUFFIX,ad.ganji.com,AdBlock\n - DOMAIN-SUFFIX,ad.gmw.cn,AdBlock\n - DOMAIN-SUFFIX,ad.go.com,AdBlock\n - DOMAIN-SUFFIX,ad.greedland.net,AdBlock\n - DOMAIN-SUFFIX,ad.gtbrowser.com,AdBlock\n - DOMAIN-SUFFIX,ad.hefei.cc,AdBlock\n - DOMAIN-SUFFIX,ad.hiiir.com,AdBlock\n - DOMAIN-SUFFIX,ad.holaq.com,AdBlock\n - DOMAIN-SUFFIX,ad.hot-mob.com,AdBlock\n - DOMAIN-SUFFIX,ad.house365.com,AdBlock\n - DOMAIN-SUFFIX,ad.huajiao.com,AdBlock\n - DOMAIN-SUFFIX,ad.ibookstar.com,AdBlock\n - DOMAIN-SUFFIX,ad.icasthq.com,AdBlock\n - DOMAIN-SUFFIX,ad.idgtn.net,AdBlock\n - DOMAIN-SUFFIX,ad.iloveinterracial.com,AdBlock\n - DOMAIN-SUFFIX,ad.ipadview.com,AdBlock\n - DOMAIN-SUFFIX,ad.jamba.net,AdBlock\n - DOMAIN-SUFFIX,ad.jamster.co.uk,AdBlock\n - DOMAIN-SUFFIX,ad.jamster.com,AdBlock\n - DOMAIN-SUFFIX,ad.jiemian.com,AdBlock\n - DOMAIN-SUFFIX,ad.jsnbrynb.com,AdBlock\n - DOMAIN-SUFFIX,ad.jxnews.com.cn,AdBlock\n - DOMAIN-SUFFIX,ad.kissanime.io,AdBlock\n - DOMAIN-SUFFIX,ad.kisscartoon.io,AdBlock\n - DOMAIN-SUFFIX,ad.leadbolt.net,AdBlock\n - DOMAIN-SUFFIX,ad.leadboltads.net,AdBlock\n - DOMAIN-SUFFIX,ad.leadboltapps.net,AdBlock\n - DOMAIN-SUFFIX,ad.leadboltmobile.net,AdBlock\n - DOMAIN-SUFFIX,ad.livere.co.kr,AdBlock\n - DOMAIN-SUFFIX,ad.lqalm.com,AdBlock\n - DOMAIN-SUFFIX,ad.lyricswire.com,AdBlock\n - DOMAIN-SUFFIX,ad.madserving.com,AdBlock\n - DOMAIN-SUFFIX,ad.mail.ru,AdBlock\n - DOMAIN-SUFFIX,ad.mail.sohu.com,AdBlock\n - DOMAIN-SUFFIX,ad.mangareader.net,AdBlock\n - DOMAIN-SUFFIX,ad.mediabong.net,AdBlock\n - DOMAIN-SUFFIX,ad.mesomorphosis.com,AdBlock\n - DOMAIN-SUFFIX,ad.mi.com,AdBlock\n - DOMAIN-SUFFIX,ad.mnt123.com,AdBlock\n - DOMAIN-SUFFIX,ad.molitv.cn,AdBlock\n - DOMAIN-SUFFIX,ad.naver.com,AdBlock\n - DOMAIN-SUFFIX,ad.netowl.jp,AdBlock\n - DOMAIN-SUFFIX,ad.newegg.com,AdBlock\n - DOMAIN-SUFFIX,ad.obuy.tw,AdBlock\n - DOMAIN-SUFFIX,ad.openmultimedia.biz,AdBlock\n - DOMAIN-SUFFIX,ad.outsidehub.com,AdBlock\n - DOMAIN-SUFFIX,ad.pandora.tv,AdBlock\n - DOMAIN-SUFFIX,ad.pchome.com.tw,AdBlock\n - DOMAIN-SUFFIX,ad.pickple.net,AdBlock\n - DOMAIN-SUFFIX,ad.pixnet.in,AdBlock\n - DOMAIN-SUFFIX,ad.pixnet.net,AdBlock\n - DOMAIN-SUFFIX,ad.player.baidu.com,AdBlock\n - DOMAIN-SUFFIX,ad.propellerads.com,AdBlock\n - DOMAIN-SUFFIX,ad.proxy.sh,AdBlock\n - DOMAIN-SUFFIX,ad.qingting.fm,AdBlock\n - DOMAIN-SUFFIX,ad.qq.com,AdBlock\n - DOMAIN-SUFFIX,ad.r.worldssl.net,AdBlock\n - DOMAIN-SUFFIX,ad.rambler.ru,AdBlock\n - DOMAIN-SUFFIX,ad.reachlocal.com,AdBlock\n - DOMAIN-SUFFIX,ad.rednet.cn,AdBlock\n - DOMAIN-SUFFIX,ad.reklamport.com,AdBlock\n - DOMAIN-SUFFIX,ad.search.ch,AdBlock\n - DOMAIN-SUFFIX,ad.seeyouyima.com,AdBlock\n - DOMAIN-SUFFIX,ad.sensismediasmart.com.au,AdBlock\n - DOMAIN-SUFFIX,ad.services.distractify.com,AdBlock\n - DOMAIN-SUFFIX,ad.shuoshuomi.com,AdBlock\n - DOMAIN-SUFFIX,ad.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,ad.sinovision.net,AdBlock\n - DOMAIN-SUFFIX,ad.slutload.com,AdBlock\n - DOMAIN-SUFFIX,ad.smartclip.net,AdBlock\n - DOMAIN-SUFFIX,ad.sohu.com,AdBlock\n - DOMAIN-SUFFIX,ad.spielothek.so,AdBlock\n - DOMAIN-SUFFIX,ad.spreaker.com,AdBlock\n - DOMAIN-SUFFIX,ad.stsywl.com,AdBlock\n - DOMAIN-SUFFIX,ad.tatatimes.com,AdBlock\n - DOMAIN-SUFFIX,ad.test.ximalaya.com,AdBlock\n - DOMAIN-SUFFIX,ad.thepaper.cn,AdBlock\n - DOMAIN-SUFFIX,ad.thisav.com,AdBlock\n - DOMAIN-SUFFIX,ad.thsi.cn,AdBlock\n - DOMAIN-SUFFIX,ad.toutiao.com,AdBlock\n - DOMAIN-SUFFIX,ad.turn.com,AdBlock\n - DOMAIN-SUFFIX,ad.unimhk.com,AdBlock\n - DOMAIN-SUFFIX,ad.userporn.com,AdBlock\n - DOMAIN-SUFFIX,ad.vidaroo.com,AdBlock\n - DOMAIN-SUFFIX,ad.vryeye.com,AdBlock\n - DOMAIN-SUFFIX,ad.walkgame.com,AdBlock\n - DOMAIN-SUFFIX,ad.wang502.com,AdBlock\n - DOMAIN-SUFFIX,ad.winningpartner.com,AdBlock\n - DOMAIN-SUFFIX,ad.winrar.com.cn,AdBlock\n - DOMAIN-SUFFIX,ad.wretch.cc,AdBlock\n - DOMAIN-SUFFIX,ad.xiaomi.com,AdBlock\n - DOMAIN-SUFFIX,ad.ximalaya.com,AdBlock\n - DOMAIN-SUFFIX,ad.xmovies8.ru,AdBlock\n - DOMAIN-SUFFIX,ad.xxguan.cn,AdBlock\n - DOMAIN-SUFFIX,ad.yeshitv.com,AdBlock\n - DOMAIN-SUFFIX,ad.yieldlab.net,AdBlock\n - DOMAIN-SUFFIX,ad.yixin.im,AdBlock\n - DOMAIN-SUFFIX,ad.ylunion.com,AdBlock\n - DOMAIN-SUFFIX,ad.zanox.com,AdBlock\n - DOMAIN-SUFFIX,ad.zdworks.com,AdBlock\n - DOMAIN-SUFFIX,ad.zhangyue.com,AdBlock\n - DOMAIN-SUFFIX,ad.zhidian3g.cn,AdBlock\n - DOMAIN-SUFFIX,ad.zuimeitianqi.com,AdBlock\n - DOMAIN-SUFFIX,ad0.bigmir.net,AdBlock\n - DOMAIN-SUFFIX,ad000000.com,AdBlock\n - DOMAIN-SUFFIX,ad1.bigmir.net,AdBlock\n - DOMAIN-SUFFIX,ad1.greedland.net,AdBlock\n - DOMAIN-SUFFIX,ad1.nend.net,AdBlock\n - DOMAIN-SUFFIX,ad1.netshelter.net,AdBlock\n - DOMAIN-SUFFIX,ad1.p5w.net,AdBlock\n - DOMAIN-SUFFIX,ad1.udn.com,AdBlock\n - DOMAIN-SUFFIX,ad1.xiaomi.com,AdBlock\n - DOMAIN-SUFFIX,ad1.yangjinyou.com,AdBlock\n - DOMAIN-SUFFIX,ad2.nend.net,AdBlock\n - DOMAIN-SUFFIX,ad2.udn.com,AdBlock\n - DOMAIN-SUFFIX,ad2.yam.com,AdBlock\n - DOMAIN-SUFFIX,ad2.yangjinyou.com,AdBlock\n - DOMAIN-SUFFIX,ad3.udn.com,AdBlock\n - DOMAIN-SUFFIX,ad4.bigmir.net,AdBlock\n - DOMAIN-SUFFIX,ad4.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,ad4.udn.com,AdBlock\n - DOMAIN-SUFFIX,ad4game.com,AdBlock\n - DOMAIN-SUFFIX,ad5.bigmir.net,AdBlock\n - DOMAIN-SUFFIX,ad6.bigmir.net,AdBlock\n - DOMAIN-SUFFIX,ad7.bigmir.net,AdBlock\n - DOMAIN-SUFFIX,ad7.com,AdBlock\n - DOMAIN-SUFFIX,ad7.on.cc,AdBlock\n - DOMAIN-SUFFIX,ad7.tagphi.net,AdBlock\n - DOMAIN-SUFFIX,ad8.adfarm1.adition.com,AdBlock\n - DOMAIN-SUFFIX,ad9377.com,AdBlock\n - DOMAIN-SUFFIX,adadapted.com,AdBlock\n - DOMAIN-SUFFIX,adadmin.house365.com,AdBlock\n - DOMAIN-SUFFIX,adadvisor.net,AdBlock\n - DOMAIN-SUFFIX,ad-android.51wnl.com,AdBlock\n - DOMAIN-SUFFIX,adap.tv,AdBlock\n - DOMAIN-SUFFIX,adapi.lenovogame.com,AdBlock\n - DOMAIN-SUFFIX,adasad.myweb.hinet.net,AdBlock\n - DOMAIN-SUFFIX,adash.m.taobao.com,AdBlock\n - DOMAIN-SUFFIX,adbana.com,AdBlock\n - DOMAIN-SUFFIX,ad-beta.flipboard.com,AdBlock\n - DOMAIN-SUFFIX,adbot.tw,AdBlock\n - DOMAIN-SUFFIX,adbox.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,ad-brix.com,AdBlock\n - DOMAIN-SUFFIX,adbuyer3.lycos.com,AdBlock\n - DOMAIN-SUFFIX,adbxb.com,AdBlock\n - DOMAIN-SUFFIX,adcast.deviantart.com,AdBlock\n - DOMAIN-SUFFIX,adcast.fblife.com,AdBlock\n - DOMAIN-SUFFIX,adccoo.cn,AdBlock\n - DOMAIN-SUFFIX,adcdn.goo.ne.jp,AdBlock\n - DOMAIN-SUFFIX,adchina.com,AdBlock\n - DOMAIN-SUFFIX,adcitrus.com,AdBlock\n - DOMAIN-SUFFIX,adcl.pchome.com.tw,AdBlock\n - DOMAIN-SUFFIX,adclick.g.doublecklick.net,AdBlock\n - DOMAIN-SUFFIX,adclient.uimserv.net,AdBlock\n - DOMAIN-SUFFIX,adclock.zdworks.com,AdBlock\n - DOMAIN-SUFFIX,adcloud.jp,AdBlock\n - DOMAIN-SUFFIX,ad-cloud.jp,AdBlock\n - DOMAIN-SUFFIX,ad-cn.jovcloud.com,AdBlock\n - DOMAIN-SUFFIX,adcolony.com,AdBlock\n - DOMAIN-SUFFIX,adcome.cn,AdBlock\n - DOMAIN-SUFFIX,adcore.lenovomm.com,AdBlock\n - DOMAIN-SUFFIX,adcount.yoka.com,AdBlock\n - DOMAIN-SUFFIX,adcr.naver.com,AdBlock\n - DOMAIN-SUFFIX,adcreative.naver.com,AdBlock\n - DOMAIN-SUFFIX,add.bugun.com.tr,AdBlock\n - DOMAIN-SUFFIX,add.dz19.net,AdBlock\n - DOMAIN-SUFFIX,add.freeimg8.com,AdBlock\n - DOMAIN-SUFFIX,add.mmyuer.com,AdBlock\n - DOMAIN-SUFFIX,addata.ku6.com,AdBlock\n - DOMAIN-SUFFIX,ad-delivery.net,AdBlock\n - DOMAIN-SUFFIX,addirector.vindicosuite.com,AdBlock\n - DOMAIN-SUFFIX,addl.easetuner.com,AdBlock\n - DOMAIN-SUFFIX,adds.weatherology.com,AdBlock\n - DOMAIN-SUFFIX,addthis.com,AdBlock\n - DOMAIN-SUFFIX,addthisedge.com,AdBlock\n - DOMAIN-SUFFIX,adeaz.com,AdBlock\n - DOMAIN-SUFFIX,ader.mobi,AdBlock\n - DOMAIN-SUFFIX,adeventtracker.spotify.com,AdBlock\n - DOMAIN-SUFFIX,adexprt.com,AdBlock\n - DOMAIN-SUFFIX,adf.dahe.cn,AdBlock\n - DOMAIN-SUFFIX,adfarm.mediaplex.com,AdBlock\n - DOMAIN-SUFFIX,adform.net,AdBlock\n - DOMAIN-SUFFIX,adfront.auction.co.kr,AdBlock\n - DOMAIN-SUFFIX,adfurikun.jp,AdBlock\n - DOMAIN-SUFFIX,adfuture.cn,AdBlock\n - DOMAIN-SUFFIX,ad-gb.mgid.com,AdBlock\n - DOMAIN-SUFFIX,adgeo.163.com,AdBlock\n - DOMAIN-SUFFIX,adhai.com,AdBlock\n - DOMAIN-SUFFIX,adhome.1fangchan.com,AdBlock\n - DOMAIN-SUFFIX,adhouyi.com,AdBlock\n - DOMAIN-SUFFIX,adi.bigmir.net,AdBlock\n - DOMAIN-SUFFIX,adi.cnool.net,AdBlock\n - DOMAIN-SUFFIX,adi2007.cnool.net,AdBlock\n - DOMAIN-SUFFIX,adimages.go.com,AdBlock\n - DOMAIN-SUFFIX,adimages.sina.com.hk,AdBlock\n - DOMAIN-SUFFIX,adimg.bbcss.com,AdBlock\n - DOMAIN-SUFFIX,adimg.cqnews.net,AdBlock\n - DOMAIN-SUFFIX,adimg.daumcdn.net,AdBlock\n - DOMAIN-SUFFIX,adimg.deviantart.net,AdBlock\n - DOMAIN-SUFFIX,adimg.mobile.sina.cn,AdBlock\n - DOMAIN-SUFFIX,adimg.qxlsjw.com,AdBlock\n - DOMAIN-SUFFIX,adimg.uimserv.net,AdBlock\n - DOMAIN-SUFFIX,adimg.uve.weibo.com,AdBlock\n - DOMAIN-SUFFIX,adimg1.chosun.com,AdBlock\n - DOMAIN-SUFFIX,adimg3.search.naver.net,AdBlock\n - DOMAIN-SUFFIX,adimgs.xici.net,AdBlock\n - DOMAIN-SUFFIX,adimp.excite.co.jp,AdBlock\n - DOMAIN-SUFFIX,adinall.com,AdBlock\n - DOMAIN-SUFFIX,adinf.cp11.ott.cibntv.net,AdBlock\n - DOMAIN-SUFFIX,adinf.voole.com,AdBlock\n - DOMAIN-SUFFIX,adinfo.aol.com,AdBlock\n - DOMAIN-SUFFIX,adinfo.ra1.xlmc.sec.miui.com,AdBlock\n - DOMAIN-SUFFIX,adinfuse.com,AdBlock\n - DOMAIN-SUFFIX,adingo.jp.eimg.jp,AdBlock\n - DOMAIN-SUFFIX,adirects.com,AdBlock\n - DOMAIN-SUFFIX,adjb.5nd.com,AdBlock\n - DOMAIN-SUFFIX,adjust.io,AdBlock\n - DOMAIN-SUFFIX,adk.funshion.com,AdBlock\n - DOMAIN-SUFFIX,adk2.co,AdBlock\n - DOMAIN-SUFFIX,adk2x.com,AdBlock\n - DOMAIN-SUFFIX,adkmob.com,AdBlock\n - DOMAIN-SUFFIX,adkongjian.com,AdBlock\n - DOMAIN-SUFFIX,adlabs-sync.rutarget.ru,AdBlock\n - DOMAIN-SUFFIX,adlaunch.moji.com,AdBlock\n - DOMAIN-SUFFIX,adlefee.com,AdBlock\n - DOMAIN-SUFFIX,adlink.shopsafe.co.nz,AdBlock\n - DOMAIN-SUFFIX,adlive.cn,AdBlock\n - DOMAIN-SUFFIX,adlocus.com,AdBlock\n - DOMAIN-SUFFIX,ad-locus.com,AdBlock\n - DOMAIN-SUFFIX,adlog.flurry.com,AdBlock\n - DOMAIN-SUFFIX,adm.10jqka.com.cn,AdBlock\n - DOMAIN-SUFFIX,adm.265g.com,AdBlock\n - DOMAIN-SUFFIX,adm.72zx.com,AdBlock\n - DOMAIN-SUFFIX,adm.86wan.com,AdBlock\n - DOMAIN-SUFFIX,adm.baidu.com,AdBlock\n - DOMAIN-SUFFIX,adm.cloud.cnfol.com,AdBlock\n - DOMAIN-SUFFIX,adm.easou.com,AdBlock\n - DOMAIN-SUFFIX,adm.funshion.com,AdBlock\n - DOMAIN-SUFFIX,adm.icast.cn,AdBlock\n - DOMAIN-SUFFIX,adm.leju.com,AdBlock\n - DOMAIN-SUFFIX,adm.leju.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,adm.myzaker.com,AdBlock\n - DOMAIN-SUFFIX,adm.xmfish.com,AdBlock\n - DOMAIN-SUFFIX,adm.zbinfo.net,AdBlock\n - DOMAIN-SUFFIX,adm.zookingsoft.com,AdBlock\n - DOMAIN-SUFFIX,adm0.autoimg.cn,AdBlock\n - DOMAIN-SUFFIX,adm1.autoimg.cn,AdBlock\n - DOMAIN-SUFFIX,adm2.autoimg.cn,AdBlock\n - DOMAIN-SUFFIX,adm3.autoimg.cn,AdBlock\n - DOMAIN-SUFFIX,admaji.com,AdBlock\n - DOMAIN-SUFFIX,admarket.21cn.com,AdBlock\n - DOMAIN-SUFFIX,admarket.mobi,AdBlock\n - DOMAIN-SUFFIX,admd.yam.com,AdBlock\n - DOMAIN-SUFFIX,admedia.com,AdBlock\n - DOMAIN-SUFFIX,admeta.vo.llnwd.net,AdBlock\n - DOMAIN-SUFFIX,admgr.qingting.fm,AdBlock\n - DOMAIN-SUFFIX,admin.cooguo.com,AdBlock\n - DOMAIN-SUFFIX,admin.louxia.org,AdBlock\n - DOMAIN-SUFFIX,admin.ninebox.cn,AdBlock\n - DOMAIN-SUFFIX,admin6.com,AdBlock\n - DOMAIN-SUFFIX,admon.cn,AdBlock\n - DOMAIN-SUFFIX,admtpmp124.com,AdBlock\n - DOMAIN-SUFFIX,admx.baixing.com,AdBlock\n - DOMAIN-SUFFIX,adn.ebay.com,AdBlock\n - DOMAIN-SUFFIX,adn.insight.ucweb.com,AdBlock\n - DOMAIN-SUFFIX,adnetpub.yaolan.com,AdBlock\n - DOMAIN-SUFFIX,adnew.wifi8.com,AdBlock\n - DOMAIN-SUFFIX,adnxs.com,AdBlock\n - DOMAIN-SUFFIX,adobe-dns.adobe.com,AdBlock\n - DOMAIN-SUFFIX,adobe-dns-2.adobe.com,AdBlock\n - DOMAIN-SUFFIX,adobe-dns-3.adobe.com,AdBlock\n - DOMAIN-SUFFIX,adomv.com,AdBlock\n - DOMAIN-SUFFIX,adp.cnool.net,AdBlock\n - DOMAIN-SUFFIX,adp.s8bbs.com,AdBlock\n - DOMAIN-SUFFIX,adp1.cnool.net,AdBlock\n - DOMAIN-SUFFIX,adpai.thepaper.cn,AdBlock\n - DOMAIN-SUFFIX,adperium.com,AdBlock\n - DOMAIN-SUFFIX,adping.qq.com,AdBlock\n - DOMAIN-SUFFIX,adplatform.vrtcal.com,AdBlock\n - DOMAIN-SUFFIX,ad-plus.cn,AdBlock\n - DOMAIN-SUFFIX,adplus.goo.mx,AdBlock\n - DOMAIN-SUFFIX,adplxmd.com,AdBlock\n - DOMAIN-SUFFIX,adpm.app.qq.com,AdBlock\n - DOMAIN-SUFFIX,adpolestar.net,AdBlock\n - DOMAIN-SUFFIX,adpro.cn,AdBlock\n - DOMAIN-SUFFIX,adpro.pro.cn,AdBlock\n - DOMAIN-SUFFIX,adpub.yaolan.com,AdBlock\n - DOMAIN-SUFFIX,adpublish.ydstatic.com,AdBlock\n - DOMAIN-SUFFIX,adpubs.yaolan.com,AdBlock\n - DOMAIN-SUFFIX,adpush.cn,AdBlock\n - DOMAIN-SUFFIX,adq.chinaso.com,AdBlock\n - DOMAIN-SUFFIX,adrdir.qq.com,AdBlock\n - DOMAIN-SUFFIX,adreal.cn,AdBlock\n - DOMAIN-SUFFIX,adres.myaora.net,AdBlock\n - DOMAIN-SUFFIX,adriver.ru,AdBlock\n - DOMAIN-SUFFIX,adriver-sync.rutarget.ru,AdBlock\n - DOMAIN-SUFFIX,adroll.com,AdBlock\n - DOMAIN-SUFFIX,adrotator.se,AdBlock\n - DOMAIN-SUFFIX,adrs.sdo.com,AdBlock\n - DOMAIN-SUFFIX,adrunnr.com,AdBlock\n - DOMAIN-SUFFIX,ads1.msads.net,AdBlock\n - DOMAIN-SUFFIX,ads1.msn.com,AdBlock\n - DOMAIN-SUFFIX,ads2.contentabc.com,AdBlock\n - DOMAIN-SUFFIX,ads2.msads.net,AdBlock\n - DOMAIN-SUFFIX,ads2.msn.com,AdBlock\n - DOMAIN-SUFFIX,ads2.opensubtitles.org,AdBlock\n - DOMAIN-SUFFIX,ads8.com,AdBlock\n - DOMAIN-SUFFIX,ads80.com,AdBlock\n - DOMAIN-SUFFIX,adsame.com,AdBlock\n - DOMAIN-SUFFIX,adsapi.manhuaren.com,AdBlock\n - DOMAIN-SUFFIX,adsatt.abcnews.starwave.com,AdBlock\n - DOMAIN-SUFFIX,adsatt.disney.starwave.com,AdBlock\n - DOMAIN-SUFFIX,adsatt.espn.go.com,AdBlock\n - DOMAIN-SUFFIX,adsatt.espn.starwave.com,AdBlock\n - DOMAIN-SUFFIX,adsatt.familyfun.starwave.com,AdBlock\n - DOMAIN-SUFFIX,adsatt.go.starwave.com,AdBlock\n - DOMAIN-SUFFIX,adsatt.movies.starwave.com,AdBlock\n - DOMAIN-SUFFIX,adscaspion.appspot.com,AdBlock\n - DOMAIN-SUFFIX,adscdn.baidu.com,AdBlock\n - DOMAIN-SUFFIX,adsclick.qq.com,AdBlock\n - DOMAIN-SUFFIX,adsclick.yx.js.cn,AdBlock\n - DOMAIN-SUFFIX,adsco.re,AdBlock\n - DOMAIN-SUFFIX,adscript.gmarket.co.kr,AdBlock\n - DOMAIN-SUFFIX,adsdk.9imobi.com,AdBlock\n - DOMAIN-SUFFIX,adsdk.dmzj.com,AdBlock\n - DOMAIN-SUFFIX,adse.test.ximalaya.com,AdBlock\n - DOMAIN-SUFFIX,adse.ximalaya.com,AdBlock\n - DOMAIN-SUFFIX,adsence.sogou.com,AdBlock\n - DOMAIN-SUFFIX,adsense.html5.qq.com,AdBlock\n - DOMAIN-SUFFIX,adserve2.tom.com,AdBlock\n - DOMAIN-SUFFIX,adsfactor.net,AdBlock\n - DOMAIN-SUFFIX,adsfile.bssdlbig.kugou.com,AdBlock\n - DOMAIN-SUFFIX,adsfile.qq.com,AdBlock\n - DOMAIN-SUFFIX,adsfs.oppomobile.com,AdBlock\n - DOMAIN-SUFFIX,adsgroup.qq.com,AdBlock\n - DOMAIN-SUFFIX,adshare.freedocast.com,AdBlock\n - DOMAIN-SUFFIX,adshmct.qq.com,AdBlock\n - DOMAIN-SUFFIX,adshmmsg.qq.com,AdBlock\n - DOMAIN-SUFFIX,adshost2.com,AdBlock\n - DOMAIN-SUFFIX,adshow.58.com,AdBlock\n - DOMAIN-SUFFIX,adshow.it168.com,AdBlock\n - DOMAIN-SUFFIX,adshows.21cn.com,AdBlock\n - DOMAIN-SUFFIX,adsin.zhangyoubao.com,AdBlock\n - DOMAIN-SUFFIX,adsinstant.com,AdBlock\n - DOMAIN-SUFFIX,adslvfile.qq.com,AdBlock\n - DOMAIN-SUFFIX,adslvseed.qq.com,AdBlock\n - DOMAIN-SUFFIX,adsmart.yicha.cn,AdBlock\n - DOMAIN-SUFFIX,adsolution.imtt.qq.com,AdBlock\n - DOMAIN-SUFFIX,adsor.openrunner.com,AdBlock\n - DOMAIN-SUFFIX,adsp.xunlei.com,AdBlock\n - DOMAIN-SUFFIX,ad-specs.guoshipartners.com,AdBlock\n - DOMAIN-SUFFIX,adsqqclick.qq.com,AdBlock\n - DOMAIN-SUFFIX,adsremote.scrippsnetworks.com,AdBlock\n - DOMAIN-SUFFIX,adsrvr.org,AdBlock\n - DOMAIN-SUFFIX,adss.dotdo.net,AdBlock\n - DOMAIN-SUFFIX,adss.yahoo.com,AdBlock\n - DOMAIN-SUFFIX,adstat.cp11.ott.cibntv.net,AdBlock\n - DOMAIN-SUFFIX,adstextview.qq.com,AdBlock\n - DOMAIN-SUFFIX,adstil.indiatimes.com,AdBlock\n - DOMAIN-SUFFIX,ad-stir.com,AdBlock\n - DOMAIN-SUFFIX,adsmind.gdtimg.com,AdBlock\n - DOMAIN-SUFFIX,adstream.123.sogoucdn.com,AdBlock\n - DOMAIN-SUFFIX,ads-twitter.com,AdBlock\n - DOMAIN-SUFFIX,ads-v-darwin.hulustream.com,AdBlock\n - DOMAIN-SUFFIX,adsunflower.com,AdBlock\n - DOMAIN-SUFFIX,adsunion.com,AdBlock\n - DOMAIN-SUFFIX,ad-survey.com,AdBlock\n - DOMAIN-SUFFIX,adsview.qq.com,AdBlock\n - DOMAIN-SUFFIX,adsview2.qq.com,AdBlock\n - DOMAIN-SUFFIX,adsymptotic.com,AdBlock\n - DOMAIN-SUFFIX,adsyndication.msn.com,AdBlock\n - DOMAIN-SUFFIX,adsys.chinacloudapp.cn,AdBlock\n - DOMAIN-SUFFIX,adsys.sinovision.net,AdBlock\n - DOMAIN-SUFFIX,adtaily.com,AdBlock\n - DOMAIN-SUFFIX,ad-tech.nbcuni.com,AdBlock\n - DOMAIN-SUFFIX,adtechjp.com,AdBlock\n - DOMAIN-SUFFIX,adtechus.com,AdBlock\n - DOMAIN-SUFFIX,adtest.theonion.com,AdBlock\n - DOMAIN-SUFFIX,adthor.com,AdBlock\n - DOMAIN-SUFFIX,adtrack.ucweb.com,AdBlock\n - DOMAIN-SUFFIX,adtrk.me,AdBlock\n - DOMAIN-SUFFIX,adui.tg.meitu.com,AdBlock\n - DOMAIN-SUFFIX,adultfriendfinder.com,AdBlock\n - DOMAIN-SUFFIX,adups.com,AdBlock\n - DOMAIN-SUFFIX,aduu.cn,AdBlock\n - DOMAIN-SUFFIX,adv.app.qq.com,AdBlock\n - DOMAIN-SUFFIX,adv.ccb.com,AdBlock\n - DOMAIN-SUFFIX,adv.fjtv.net,AdBlock\n - DOMAIN-SUFFIX,adv.jxnews.com.cn,AdBlock\n - DOMAIN-SUFFIX,adv.madserving.com,AdBlock\n - DOMAIN-SUFFIX,adv.s8bbs.com,AdBlock\n - DOMAIN-SUFFIX,adv.sec.miui.com,AdBlock\n - DOMAIN-SUFFIX,adv2.downsave.com,AdBlock\n - DOMAIN-SUFFIX,advapi.ahtv.cn,AdBlock\n - DOMAIN-SUFFIX,adver.qq.com,AdBlock\n - DOMAIN-SUFFIX,adview.cn,AdBlock\n - DOMAIN-SUFFIX,advmob.cn,AdBlock\n - DOMAIN-SUFFIX,advombat.ru,AdBlock\n - DOMAIN-SUFFIX,adwasu.wasu.tv,AdBlock\n - DOMAIN-SUFFIX,adweb.test.ximalaya.com,AdBlock\n - DOMAIN-SUFFIX,adweb.ximalaya.com,AdBlock\n - DOMAIN-SUFFIX,adwhirl.com,AdBlock\n - DOMAIN-SUFFIX,adwo.com,AdBlock\n - DOMAIN-SUFFIX,adx.adxglobal.com,AdBlock\n - DOMAIN-SUFFIX,adx.chip.de,AdBlock\n - DOMAIN-SUFFIX,adx.dlads.cn,AdBlock\n - DOMAIN-SUFFIX,adx.kat.ph,AdBlock\n - DOMAIN-SUFFIX,adx.pro.cn,AdBlock\n - DOMAIN-SUFFIX,adx.xiaodutv.com,AdBlock\n - DOMAIN-SUFFIX,adx3.iq39.com,AdBlock\n - DOMAIN-SUFFIX,adxmi.com,AdBlock\n - DOMAIN-SUFFIX,adxpansion.com,AdBlock\n - DOMAIN-SUFFIX,adxserver.ad.cmvideo.cn,AdBlock\n - DOMAIN-SUFFIX,adytx.com,AdBlock\n - DOMAIN-SUFFIX,adyun.com,AdBlock\n - DOMAIN-SUFFIX,adz.zwee.ly,AdBlock\n - DOMAIN-SUFFIX,adzerk.net,AdBlock\n - DOMAIN-SUFFIX,aec.shjk123.net,AdBlock\n - DOMAIN-SUFFIX,aecpm.alicdn.com,AdBlock\n - DOMAIN-SUFFIX,ae-gb.mgid.com,AdBlock\n - DOMAIN-SUFFIX,aercxy.com,AdBlock\n - DOMAIN-SUFFIX,aerserv.com,AdBlock\n - DOMAIN-SUFFIX,aes01.com,AdBlock\n - DOMAIN-SUFFIX,afd.baidu.com,AdBlock\n - DOMAIN-SUFFIX,afd.l.google.com,AdBlock\n - DOMAIN-SUFFIX,aff.eteachergroup.com,AdBlock\n - DOMAIN-SUFFIX,aff.lmgtfy.com,AdBlock\n - DOMAIN-SUFFIX,aff.marathonbet.com,AdBlock\n - DOMAIN-SUFFIX,aff.svjump.com,AdBlock\n - DOMAIN-SUFFIX,affil.mupromo.com,AdBlock\n - DOMAIN-SUFFIX,affiliategroove.com,AdBlock\n - DOMAIN-SUFFIX,affiliateprogram.keywordspy.com,AdBlock\n - DOMAIN-SUFFIX,affiliates.allposters.com,AdBlock\n - DOMAIN-SUFFIX,affiliates.goodvibes.com,AdBlock\n - DOMAIN-SUFFIX,affiliates.thrixxx.com,AdBlock\n - DOMAIN-SUFFIX,affiliatesmedia.sbobet.com,AdBlock\n - DOMAIN-SUFFIX,affiliation.fotovista.com,AdBlock\n - DOMAIN-SUFFIX,afjlb.com,AdBlock\n - DOMAIN-SUFFIX,afp.alicdn.com,AdBlock\n - DOMAIN-SUFFIX,afp.chinanews.com,AdBlock\n - DOMAIN-SUFFIX,afp.csbew.com,AdBlock\n - DOMAIN-SUFFIX,afp.m1905.com,AdBlock\n - DOMAIN-SUFFIX,afp.wasu.cn,AdBlock\n - DOMAIN-SUFFIX,afp.zol-img.com.cn,AdBlock\n - DOMAIN-SUFFIX,afpcreative.wasu.cn,AdBlock\n - DOMAIN-SUFFIX,afpimages.eastday,AdBlock\n - DOMAIN-SUFFIX,afpimages.eastday.com,AdBlock\n - DOMAIN-SUFFIX,afpmm.alicdn.com,AdBlock\n - DOMAIN-SUFFIX,afptrack.csbew.com,AdBlock\n - DOMAIN-SUFFIX,ag.nukefans.net,AdBlock\n - DOMAIN-SUFFIX,agenda.complex.com,AdBlock\n - DOMAIN-SUFFIX,ag-gb.marketgid.com,AdBlock\n - DOMAIN-SUFFIX,agn.aty.cp45.ott.cibntv.net,AdBlock\n - DOMAIN-SUFFIX,agn.aty.snmsohu.aisee.tv,AdBlock\n - DOMAIN-SUFFIX,agoodm.m.taobao.com,AdBlock\n - DOMAIN-SUFFIX,agr.voiceads.cn,AdBlock\n - DOMAIN-SUFFIX,agrant.cn,AdBlock\n - DOMAIN-SUFFIX,agrantsem.com,AdBlock\n - DOMAIN-SUFFIX,ahhuazhen.com,AdBlock\n - DOMAIN-SUFFIX,ahyau.com,AdBlock\n - DOMAIN-SUFFIX,ahyuns.com,AdBlock\n - DOMAIN-SUFFIX,ai.bioon.com,AdBlock\n - DOMAIN-SUFFIX,ai.m.taobao.com,AdBlock\n - DOMAIN-SUFFIX,ai.taobao.com,AdBlock\n - DOMAIN-SUFFIX,ai.xinju.cc,AdBlock\n - DOMAIN-SUFFIX,ai.yimg.jp,AdBlock\n - DOMAIN-SUFFIX,aibangzs.com,AdBlock\n - DOMAIN-SUFFIX,aiclk.com,AdBlock\n - DOMAIN-SUFFIX,aicydb.com,AdBlock\n - DOMAIN-SUFFIX,aid.chinayk.com,AdBlock\n - DOMAIN-SUFFIX,aider-res.meizu.com,AdBlock\n - DOMAIN-SUFFIX,aihaoduo.cn,AdBlock\n - DOMAIN-SUFFIX,aikan6.com,AdBlock\n - DOMAIN-SUFFIX,ailicee.com,AdBlock\n - DOMAIN-SUFFIX,aim.yoyi.com.cn,AdBlock\n - DOMAIN-SUFFIX,air.yoyi.com.cn,AdBlock\n - DOMAIN-SUFFIX,airpush.com,AdBlock\n - DOMAIN-SUFFIX,airpushmarketing.s3.amazonaws.com,AdBlock\n - DOMAIN-SUFFIX,ais.abacast.com,AdBlock\n - DOMAIN-SUFFIX,aishang.bid,AdBlock\n - DOMAIN-SUFFIX,aishiguolong.com,AdBlock\n - DOMAIN-SUFFIX,aishowbger.com,AdBlock\n - DOMAIN-SUFFIX,aiwen.cc,AdBlock\n - DOMAIN-SUFFIX,ajapk.com,AdBlock\n - DOMAIN-SUFFIX,ajaxcdn.org,AdBlock\n - DOMAIN-SUFFIX,aj-gb.mgid.com,AdBlock\n - DOMAIN-SUFFIX,ajhdf.com,AdBlock\n - DOMAIN-SUFFIX,ajialive.com,AdBlock\n - DOMAIN-SUFFIX,ajnad.aljazeera.net,AdBlock\n - DOMAIN-SUFFIX,ajuhd.com,AdBlock\n - DOMAIN-SUFFIX,ak.sascdn.com,AdBlock\n - DOMAIN-SUFFIX,ak47.cooguo.com,AdBlock\n - DOMAIN-SUFFIX,akrwi.cn,AdBlock\n - DOMAIN-SUFFIX,akuai.top,AdBlock\n - DOMAIN-SUFFIX,akxsrsdbursfpx.bid,AdBlock\n - DOMAIN-SUFFIX,alertserver.ushaqi.com,AdBlock\n - DOMAIN-SUFFIX,alipay.dajiadou6.com,AdBlock\n - DOMAIN-SUFFIX,aliqqjd.cn,AdBlock\n - DOMAIN-SUFFIX,alisinak.com,AdBlock\n - DOMAIN-SUFFIX,alissl.ucdl.pp.uc.cn,AdBlock\n - DOMAIN-SUFFIX,alistatic.cn,AdBlock\n - DOMAIN-SUFFIX,alitianxia168.com,AdBlock\n - DOMAIN-SUFFIX,alitui.weibo.com,AdBlock\n - DOMAIN-SUFFIX,aliunion.cn.yahoo.com,AdBlock\n - DOMAIN-SUFFIX,aliyuncss.com,AdBlock\n - DOMAIN-SUFFIX,aliyunxin.com,AdBlock\n - DOMAIN-SUFFIX,all.orfr.adgtw.orangeads.fr,AdBlock\n - DOMAIN-SUFFIX,all.rising.com.cn,AdBlock\n - DOMAIN-SUFFIX,allnews.uodoo.com,AdBlock\n - DOMAIN-SUFFIX,allxin.com,AdBlock\n - DOMAIN-SUFFIX,als.baidu.com,AdBlock\n - DOMAIN-SUFFIX,alvares.esportsheaven.com,AdBlock\n - DOMAIN-SUFFIX,am.6park.com,AdBlock\n - DOMAIN-SUFFIX,am.g.ireader.com,AdBlock\n - DOMAIN-SUFFIX,am.szhome.com,AdBlock\n - DOMAIN-SUFFIX,am.zdnet.com.cn,AdBlock\n - DOMAIN-SUFFIX,am15.net,AdBlock\n - DOMAIN-SUFFIX,amazingmagics.com,AdBlock\n - DOMAIN-SUFFIX,amazon-adsystem.com,AdBlock\n - DOMAIN-SUFFIX,amdc.m.taobao.com,AdBlock\n - DOMAIN-SUFFIX,amfi.gou.sogou.com,AdBlock\n - DOMAIN-SUFFIX,amiok.org,AdBlock\n - DOMAIN-SUFFIX,amps.yoyi.com.cn,AdBlock\n - DOMAIN-SUFFIX,ams.fx678.com,AdBlock\n - DOMAIN-SUFFIX,ams.lenovomm.com,AdBlock\n - DOMAIN-SUFFIX,a-m-s.poco.cn,AdBlock\n - DOMAIN-SUFFIX,amz.steamprices.com,AdBlock\n - DOMAIN-SUFFIX,an.m.liebao.cn,AdBlock\n - DOMAIN-SUFFIX,an.wikigifth.com,AdBlock\n - DOMAIN-SUFFIX,an.yandex.ru,AdBlock\n - DOMAIN-SUFFIX,ana.tatahn.com,AdBlock\n - DOMAIN-SUFFIX,analy.qq.com,AdBlock\n - DOMAIN-SUFFIX,andmejs.com,AdBlock\n - DOMAIN-SUFFIX,android.push.126.net,AdBlock\n - DOMAIN-SUFFIX,android.rqd.qq.com,AdBlock\n - DOMAIN-SUFFIX,androidlog.shouji.baofeng.com,AdBlock\n - DOMAIN-SUFFIX,android-lrcresource.wps.cn,AdBlock\n - DOMAIN-SUFFIX,andrqd.play.aiseet.atianqi.com,AdBlock\n - DOMAIN-SUFFIX,anfeng.com,AdBlock\n - DOMAIN-SUFFIX,angsrvr.com,AdBlock\n - DOMAIN-SUFFIX,anioscp.com,AdBlock\n - DOMAIN-SUFFIX,ann5.net,AdBlock\n - DOMAIN-SUFFIX,anquan.baidu.com,AdBlock\n - DOMAIN-SUFFIX,anquan.org,AdBlock\n - DOMAIN-SUFFIX,anreson.net,AdBlock\n - DOMAIN-SUFFIX,antivirus.baidu.com,AdBlock\n - DOMAIN-SUFFIX,anyangruisi.com,AdBlock\n - DOMAIN-SUFFIX,anysdk.com,AdBlock\n - DOMAIN-SUFFIX,aodongjiaosu.com,AdBlock\n - DOMAIN-SUFFIX,aombjl099.com,AdBlock\n - DOMAIN-SUFFIX,aoodoo.feng.com,AdBlock\n - DOMAIN-SUFFIX,aoodoo.weiphone.com,AdBlock\n - DOMAIN-SUFFIX,aos.wall.youmi.net,AdBlock\n - DOMAIN-SUFFIX,aos-creative.prf.hn,AdBlock\n - DOMAIN-SUFFIX,apas.aipai.com,AdBlock\n - DOMAIN-SUFFIX,api.0.0.0.0.cn,AdBlock\n - DOMAIN-SUFFIX,api.adv.ott.cibntv.net,AdBlock\n - DOMAIN-SUFFIX,api.ahjinshu.com,AdBlock\n - DOMAIN-SUFFIX,api.android.dianru.com,AdBlock\n - DOMAIN-SUFFIX,api.anti.wauee.com,AdBlock\n - DOMAIN-SUFFIX,api.appodeal.com,AdBlock\n - DOMAIN-SUFFIX,api.apps.sina.cn,AdBlock\n - DOMAIN-SUFFIX,api.bailingjiankang.com,AdBlock\n - DOMAIN-SUFFIX,api.bs.zui.com,AdBlock\n - DOMAIN-SUFFIX,api.cmt.mob.com,AdBlock\n - DOMAIN-SUFFIX,api.coolguang.com,AdBlock\n - DOMAIN-SUFFIX,api.dewmobile.net,AdBlock\n - DOMAIN-SUFFIX,api.dianru.com,AdBlock\n - DOMAIN-SUFFIX,api.doumob.com,AdBlock\n - DOMAIN-SUFFIX,api.dreamfull.cn,AdBlock\n - DOMAIN-SUFFIX,api.dsp.yhd.com,AdBlock\n - DOMAIN-SUFFIX,api.exc.mob.com,AdBlock\n - DOMAIN-SUFFIX,api.g1.junfull.com,AdBlock\n - DOMAIN-SUFFIX,api.g2.junfull.com,AdBlock\n - DOMAIN-SUFFIX,api.gi.igexin.com,AdBlock\n - DOMAIN-SUFFIX,api.goulegu.com,AdBlock\n - DOMAIN-SUFFIX,api.growingio.com,AdBlock\n - DOMAIN-SUFFIX,api.iapps.ifeng.com,AdBlock\n - DOMAIN-SUFFIX,api.iimedia.cn,AdBlock\n - DOMAIN-SUFFIX,api.ijunhai.com,AdBlock\n - DOMAIN-SUFFIX,api.itaoxiaoshuo.com,AdBlock\n - DOMAIN-SUFFIX,api.joybj.com,AdBlock\n - DOMAIN-SUFFIX,api.ketedata.com,AdBlock\n - DOMAIN-SUFFIX,api.koudaikj.com,AdBlock\n - DOMAIN-SUFFIX,api.leadbolt.net,AdBlock\n - DOMAIN-SUFFIX,api.mobgi.com,AdBlock\n - DOMAIN-SUFFIX,api.mobula.sdk.duapps.com,AdBlock\n - DOMAIN-SUFFIX,api.moogos.com,AdBlock\n - DOMAIN-SUFFIX,api.mp.uc.cn,AdBlock\n - DOMAIN-SUFFIX,api.newad.ifeng.com,AdBlock\n - DOMAIN-SUFFIX,api.newbelden.com,AdBlock\n - DOMAIN-SUFFIX,api.open.uc.cn,AdBlock\n - DOMAIN-SUFFIX,api.pingstart.com,AdBlock\n - DOMAIN-SUFFIX,api.ppoi.org,AdBlock\n - DOMAIN-SUFFIX,api.primecaster.net,AdBlock\n - DOMAIN-SUFFIX,api.push.daoyoudao.com,AdBlock\n - DOMAIN-SUFFIX,api.ra2.xlmc.sec.miui.com,AdBlock\n - DOMAIN-SUFFIX,api.rees46.com,AdBlock\n - DOMAIN-SUFFIX,api.rideraid.net,AdBlock\n - DOMAIN-SUFFIX,api.share.mob.com,AdBlock\n - DOMAIN-SUFFIX,api.shuzilm.cn,AdBlock\n - DOMAIN-SUFFIX,api.similarweb.com,AdBlock\n - DOMAIN-SUFFIX,api.tr.blismedia.com,AdBlock\n - DOMAIN-SUFFIX,api.tw06.xlmc.sec.miui.com,AdBlock\n - DOMAIN-SUFFIX,api.ujian.cc,AdBlock\n - DOMAIN-SUFFIX,api.union.vip.com,AdBlock\n - DOMAIN-SUFFIX,api.uniplayad.com,AdBlock\n - DOMAIN-SUFFIX,api.userstyles.org,AdBlock\n - DOMAIN-SUFFIX,api.viglink.com,AdBlock\n - DOMAIN-SUFFIX,api.waptest.taobao.com,AdBlock\n - DOMAIN-SUFFIX,api.whizzone.com,AdBlock\n - DOMAIN-SUFFIX,api.xk.miui.com,AdBlock\n - DOMAIN-SUFFIX,api.y.igexin.com,AdBlock\n - DOMAIN-SUFFIX,api.youxiaoad.com,AdBlock\n - DOMAIN-SUFFIX,api.zol.com,AdBlock\n - DOMAIN-SUFFIX,api2.play.cn,AdBlock\n - DOMAIN-SUFFIX,api-flow.flyme.cn,AdBlock\n - DOMAIN-SUFFIX,api-game.meizu.com,AdBlock\n - DOMAIN-SUFFIX,apihk.growingio.com,AdBlock\n - DOMAIN-SUFFIX,api-push.meizu.com,AdBlock\n - DOMAIN-SUFFIX,api-shoulei-ssl.xunlei.com,AdBlock\n - DOMAIN-SUFFIX,apisoft.df0535.com,AdBlock\n - DOMAIN-SUFFIX,apk.idate520.com,AdBlock\n - DOMAIN-SUFFIX,apk.supfast.net,AdBlock\n - DOMAIN-SUFFIX,apkdo.com,AdBlock\n - DOMAIN-SUFFIX,apkinfo.voole.com,AdBlock\n - DOMAIN-SUFFIX,apklog.cp11.ott.cibntv.net,AdBlock\n - DOMAIN-SUFFIX,apnmedia.ask.com,AdBlock\n - DOMAIN-SUFFIX,apns.ios.ijinshan.com,AdBlock\n - DOMAIN-SUFFIX,apoll.m.taobao.com,AdBlock\n - DOMAIN-SUFFIX,apollo.caixin.com,AdBlock\n - DOMAIN-SUFFIX,app.3987.com,AdBlock\n - DOMAIN-SUFFIX,app.9yyg.cn,AdBlock\n - DOMAIN-SUFFIX,app.abc000.today,AdBlock\n - DOMAIN-SUFFIX,app.acm.dzwww.com,AdBlock\n - DOMAIN-SUFFIX,app.eduancm.com,AdBlock\n - DOMAIN-SUFFIX,app.houyi.baofeng.net,AdBlock\n - DOMAIN-SUFFIX,app.hytdsm.com,AdBlock\n - DOMAIN-SUFFIX,app.ibaiducdn.com,AdBlock\n - DOMAIN-SUFFIX,app.jgyee.com,AdBlock\n - DOMAIN-SUFFIX,app.jiuzhilan.com,AdBlock\n - DOMAIN-SUFFIX,app.juwang.com,AdBlock\n - DOMAIN-SUFFIX,app.lz55.cn,AdBlock\n - DOMAIN-SUFFIX,app.moji001.com,AdBlock\n - DOMAIN-SUFFIX,app.starschina.com,AdBlock\n - DOMAIN-SUFFIX,app.tanwan.com,AdBlock\n - DOMAIN-SUFFIX,app.uu.cc,AdBlock\n - DOMAIN-SUFFIX,app.waps.cn,AdBlock\n - DOMAIN-SUFFIX,app.wapx.cn,AdBlock\n - DOMAIN-SUFFIX,app.wumii.com,AdBlock\n - DOMAIN-SUFFIX,app.xizi.com,AdBlock\n - DOMAIN-SUFFIX,app.xyjqy.com,AdBlock\n - DOMAIN-SUFFIX,app01.nodes.gslb.mi-idc.com,AdBlock\n - DOMAIN-SUFFIX,app02.nodes.gslb.mi-idc.com,AdBlock\n - DOMAIN-SUFFIX,appads.com,AdBlock\n - DOMAIN-SUFFIX,appboy.com,AdBlock\n - DOMAIN-SUFFIX,appc.baidu.com,AdBlock\n - DOMAIN-SUFFIX,appcdn.wapx.cn,AdBlock\n - DOMAIN-SUFFIX,appcdn.wapx.com,AdBlock\n - DOMAIN-SUFFIX,appcpa.net,AdBlock\n - DOMAIN-SUFFIX,appdriver.cn,AdBlock\n - DOMAIN-SUFFIX,appdriver.com.cn,AdBlock\n - DOMAIN-SUFFIX,appfh.com,AdBlock\n - DOMAIN-SUFFIX,app-g.39.net,AdBlock\n - DOMAIN-SUFFIX,appget.cn,AdBlock\n - DOMAIN-SUFFIX,appgift.sinaapp.com,AdBlock\n - DOMAIN-SUFFIX,appjiagu.com,AdBlock\n - DOMAIN-SUFFIX,applifier.com,AdBlock\n - DOMAIN-SUFFIX,applog.uc.cn,AdBlock\n - DOMAIN-SUFFIX,applogios.uc.cn,AdBlock\n - DOMAIN-SUFFIX,applovin.com,AdBlock\n - DOMAIN-SUFFIX,applvn.com,AdBlock\n - DOMAIN-SUFFIX,app-monitor.ele.me,AdBlock\n - DOMAIN-SUFFIX,appnext.com,AdBlock\n - DOMAIN-SUFFIX,appodealx.com,AdBlock\n - DOMAIN-SUFFIX,apppic.yingyongbei.com,AdBlock\n - DOMAIN-SUFFIX,apps.mobilityware.com,AdBlock\n - DOMAIN-SUFFIX,apps.outfit7.com,AdBlock\n - DOMAIN-SUFFIX,apps.supfast.net,AdBlock\n - DOMAIN-SUFFIX,apps2.outfit7.com,AdBlock\n - DOMAIN-SUFFIX,appsdk.tanv.com,AdBlock\n - DOMAIN-SUFFIX,appservices.comcsoft.com,AdBlock\n - DOMAIN-SUFFIX,appsflyer.com,AdBlock\n - DOMAIN-SUFFIX,appspromote.wostore.cn,AdBlock\n - DOMAIN-SUFFIX,appsrv1.madserving.com,AdBlock\n - DOMAIN-SUFFIX,appsrv4.madserving.com,AdBlock\n - DOMAIN-SUFFIX,appsupdate.sinaapp.com,AdBlock\n - DOMAIN-SUFFIX,appsupport.stargame.com,AdBlock\n - DOMAIN-SUFFIX,apptentive.com,AdBlock\n - DOMAIN-SUFFIX,appuu.cn,AdBlock\n - DOMAIN-SUFFIX,apt.qumi.com,AdBlock\n - DOMAIN-SUFFIX,aqgyju.cn,AdBlock\n - DOMAIN-SUFFIX,aqqgli3vle.bid,AdBlock\n - DOMAIN-SUFFIX,aqw.quanliyouxi.cn,AdBlock\n - DOMAIN-SUFFIX,ar.atwola.com,AdBlock\n - DOMAIN-SUFFIX,ar1.atwola.com,AdBlock\n - DOMAIN-SUFFIX,ar7.atwola.com,AdBlock\n - DOMAIN-SUFFIX,ar9.atwola.com,AdBlock\n - DOMAIN-SUFFIX,aralego.com,AdBlock\n - DOMAIN-SUFFIX,ard.ihookup.com,AdBlock\n - DOMAIN-SUFFIX,ard.sweetdiscreet.com,AdBlock\n - DOMAIN-SUFFIX,ard.yahoo.co.jp,AdBlock\n - DOMAIN-SUFFIX,ardmall.com,AdBlock\n - DOMAIN-SUFFIX,arealx.com,AdBlock\n - DOMAIN-SUFFIX,aries.mzres.com,AdBlock\n - DOMAIN-SUFFIX,ark.cocounion.com,AdBlock\n - DOMAIN-SUFFIX,ark.cp21.ott.cibntv.net,AdBlock\n - DOMAIN-SUFFIX,art.theta.sogoucdn.com,AdBlock\n - DOMAIN-SUFFIX,as.bjmama.net,AdBlock\n - DOMAIN-SUFFIX,as.casalemedia.com,AdBlock\n - DOMAIN-SUFFIX,as.inbox.com,AdBlock\n - DOMAIN-SUFFIX,as.kejet.com,AdBlock\n - DOMAIN-SUFFIX,as.kejet.net,AdBlock\n - DOMAIN-SUFFIX,as.sinahk.net,AdBlock\n - DOMAIN-SUFFIX,as.trklinklog.com,AdBlock\n - DOMAIN-SUFFIX,as.yuewz.com,AdBlock\n - DOMAIN-SUFFIX,asd.projectfreetv.so,AdBlock\n - DOMAIN-SUFFIX,asearch.alicdn.com,AdBlock\n - DOMAIN-SUFFIX,ashiping.com,AdBlock\n - DOMAIN-SUFFIX,ashow.pcpop.com,AdBlock\n - DOMAIN-SUFFIX,asia.marketo.com,AdBlock\n - DOMAIN-SUFFIX,ask.gaykes.com,AdBlock\n - DOMAIN-SUFFIX,assets.210189.com,AdBlock\n - DOMAIN-SUFFIX,assets.2343sdxs.com,AdBlock\n - DOMAIN-SUFFIX,assets.258pcf.com,AdBlock\n - DOMAIN-SUFFIX,assets.258ydh.com,AdBlock\n - DOMAIN-SUFFIX,assets.easou.com,AdBlock\n - DOMAIN-SUFFIX,asv.nuggad.net,AdBlock\n - DOMAIN-SUFFIX,aswgbzsw.xingtangshuo.com,AdBlock\n - DOMAIN-SUFFIX,aswl.d3kdh34.pw,AdBlock\n - DOMAIN-SUFFIX,aswl.dfs3e4.pw,AdBlock\n - DOMAIN-SUFFIX,aswl.zjhim.com,AdBlock\n - DOMAIN-SUFFIX,aswlx.cn,AdBlock\n - DOMAIN-SUFFIX,at.atwola.com,AdBlock\n - DOMAIN-SUFFIX,at.mct01.com,AdBlock\n - DOMAIN-SUFFIX,at98.com,AdBlock\n - DOMAIN-SUFFIX,atanx.alicdn.com,AdBlock\n - DOMAIN-SUFFIX,atanx2.alicdn.com,AdBlock\n - DOMAIN-SUFFIX,atas.io,AdBlock\n - DOMAIN-SUFFIX,atcryp.com,AdBlock\n - DOMAIN-SUFFIX,atdmt.com,AdBlock\n - DOMAIN-SUFFIX,athena.wan.sogou.com,AdBlock\n - DOMAIN-SUFFIX,atiws.aipai.com,AdBlock\n - DOMAIN-SUFFIX,atm.punchbox.org,AdBlock\n - DOMAIN-SUFFIX,atm.sina.com,AdBlock\n - DOMAIN-SUFFIX,atm.yoyi.com.cn,AdBlock\n - DOMAIN-SUFFIX,atomicblast.lol,AdBlock\n - DOMAIN-SUFFIX,atplay.cn,AdBlock\n - DOMAIN-SUFFIX,att.stargame.com,AdBlock\n - DOMAIN-SUFFIX,attach.s8bbs.com,AdBlock\n - DOMAIN-SUFFIX,au.youmi.net,AdBlock\n - DOMAIN-SUFFIX,audience.network,AdBlock\n - DOMAIN-SUFFIX,authedmine.com,AdBlock\n - DOMAIN-SUFFIX,avn.innity.com,AdBlock\n - DOMAIN-SUFFIX,avpa.dzone.com,AdBlock\n - DOMAIN-SUFFIX,avualrhg9p.bid,AdBlock\n - DOMAIN-SUFFIX,aw.kejet.net,AdBlock\n - DOMAIN-SUFFIX,award.sitekeuring.net,AdBlock\n - DOMAIN-SUFFIX,awempire.com,AdBlock\n - DOMAIN-SUFFIX,awkjs.com,AdBlock\n - DOMAIN-SUFFIX,awyys.com,AdBlock\n - DOMAIN-SUFFIX,ax.120ask.com,AdBlock\n - DOMAIN-SUFFIX,ax.ggfeng.com,AdBlock\n - DOMAIN-SUFFIX,axhxa.com,AdBlock\n - DOMAIN-SUFFIX,axiba66.com,AdBlock\n - DOMAIN-SUFFIX,axkxy.com,AdBlock\n - DOMAIN-SUFFIX,ayabreya.xyz,AdBlock\n - DOMAIN-SUFFIX,b.53yao.com,AdBlock\n - DOMAIN-SUFFIX,b.77vcd.com,AdBlock\n - DOMAIN-SUFFIX,b.9dreams.net,AdBlock\n - DOMAIN-SUFFIX,b.ads1.msn.com,AdBlock\n - DOMAIN-SUFFIX,b.aowugame.com,AdBlock\n - DOMAIN-SUFFIX,b.babylon.com,AdBlock\n - DOMAIN-SUFFIX,b.baiy.net,AdBlock\n - DOMAIN-SUFFIX,b.bst.126.net,AdBlock\n - DOMAIN-SUFFIX,b.clkservice.youdao.com,AdBlock\n - DOMAIN-SUFFIX,b.code.tanwanyx.com,AdBlock\n - DOMAIN-SUFFIX,b.cyone.com.cn,AdBlock\n - DOMAIN-SUFFIX,b.epinv.com,AdBlock\n - DOMAIN-SUFFIX,b.flyreading.cn,AdBlock\n - DOMAIN-SUFFIX,b.gwylm.com,AdBlock\n - DOMAIN-SUFFIX,b.kuangtuiguoo18888.com,AdBlock\n - DOMAIN-SUFFIX,b.livesport.eu,AdBlock\n - DOMAIN-SUFFIX,b.localpages.com,AdBlock\n - DOMAIN-SUFFIX,b.nvrentao8.com,AdBlock\n - DOMAIN-SUFFIX,b.qchannel03.cn,AdBlock\n - DOMAIN-SUFFIX,b.rifub.com,AdBlock\n - DOMAIN-SUFFIX,b.scorecardresearch.com,AdBlock\n - DOMAIN-SUFFIX,b.thefile.me,AdBlock\n - DOMAIN-SUFFIX,b.xcafe.com,AdBlock\n - DOMAIN-SUFFIX,b0.qinsx.cn,AdBlock\n - DOMAIN-SUFFIX,b1.51scw.net,AdBlock\n - DOMAIN-SUFFIX,b1.91jucai.com,AdBlock\n - DOMAIN-SUFFIX,b1.c1km4.com,AdBlock\n - DOMAIN-SUFFIX,b17.8794.cn,AdBlock\n - DOMAIN-SUFFIX,b17.shangc.net,AdBlock\n - DOMAIN-SUFFIX,b17.xiumu.cn,AdBlock\n - DOMAIN-SUFFIX,b1sync.zemanta.com,AdBlock\n - DOMAIN-SUFFIX,b4xuj.zzhhts.com,AdBlock\n - DOMAIN-SUFFIX,b7nkd.cn,AdBlock\n - DOMAIN-SUFFIX,b92.putniktravel.com,AdBlock\n - DOMAIN-SUFFIX,b9377h.com,AdBlock\n - DOMAIN-SUFFIX,b99u.top,AdBlock\n - DOMAIN-SUFFIX,ba.ccm2.net,AdBlock\n - DOMAIN-SUFFIX,ba.fqzds.com,AdBlock\n - DOMAIN-SUFFIX,ba.kioskea.net,AdBlock\n - DOMAIN-SUFFIX,baby.yf898.com,AdBlock\n - DOMAIN-SUFFIX,backup.lumion3d.com,AdBlock\n - DOMAIN-SUFFIX,backup.lumion3d.net,AdBlock\n - DOMAIN-SUFFIX,bad1.51gxqm.com,AdBlock\n - DOMAIN-SUFFIX,badad.googleplex.com,AdBlock\n - DOMAIN-SUFFIX,badao37.net,AdBlock\n - DOMAIN-SUFFIX,bai3.gushiwen.org,AdBlock\n - DOMAIN-SUFFIX,baiapk.com,AdBlock\n - DOMAIN-SUFFIX,baichuan.baidu.com,AdBlock\n - DOMAIN-SUFFIX,baidu.cybcyw.com,AdBlock\n - DOMAIN-SUFFIX,baidu.dsp.tansuotv.com,AdBlock\n - DOMAIN-SUFFIX,baidu.greenxf.cn,AdBlock\n - DOMAIN-SUFFIX,baidu.jz5u.net,AdBlock\n - DOMAIN-SUFFIX,baiduace.com,AdBlock\n - DOMAIN-SUFFIX,baidujs.cnys.com,AdBlock\n - DOMAIN-SUFFIX,baidulao.com,AdBlock\n - DOMAIN-SUFFIX,baidustatic.com,AdBlock\n - DOMAIN-SUFFIX,baidut.github.io,AdBlock\n - DOMAIN-SUFFIX,baidutv.baidu.com,AdBlock\n - DOMAIN-SUFFIX,baidu-union-js.xiachufang.com,AdBlock\n - DOMAIN-SUFFIX,baidu-union-pos.xiachufang.com,AdBlock\n - DOMAIN-SUFFIX,baiduyubaidu.com,AdBlock\n - DOMAIN-SUFFIX,baiduzhidahao.cc,AdBlock\n - DOMAIN-SUFFIX,baifen.music.baidu.com,AdBlock\n - DOMAIN-SUFFIX,baifendian.com,AdBlock\n - DOMAIN-SUFFIX,baigm.com,AdBlock\n - DOMAIN-SUFFIX,baiwanchuangyi.com,AdBlock\n - DOMAIN-SUFFIX,bam.nr-data.net,AdBlock\n - DOMAIN-SUFFIX,banlv.baidu.com,AdBlock\n - DOMAIN-SUFFIX,banmamedia.com,AdBlock\n - DOMAIN-SUFFIX,bannedbook.org,AdBlock\n - DOMAIN-SUFFIX,banner.101xp.com,AdBlock\n - DOMAIN-SUFFIX,banner.3ddownloads.com,AdBlock\n - DOMAIN-SUFFIX,banner.automotiveworld.com,AdBlock\n - DOMAIN-SUFFIX,banner.cooguo.com,AdBlock\n - DOMAIN-SUFFIX,banner.europacasino.com,AdBlock\n - DOMAIN-SUFFIX,banner.itweb.co.za,AdBlock\n - DOMAIN-SUFFIX,banner.telefragged.com,AdBlock\n - DOMAIN-SUFFIX,banner.titancasino.com,AdBlock\n - DOMAIN-SUFFIX,banner1.pornhost.com,AdBlock\n - DOMAIN-SUFFIX,banners.beevpn.com,AdBlock\n - DOMAIN-SUFFIX,banners.beted.com,AdBlock\n - DOMAIN-SUFFIX,banners.cams.com,AdBlock\n - DOMAIN-SUFFIX,banners.clubworldgroup.com,AdBlock\n - DOMAIN-SUFFIX,banners.expressindia.com,AdBlock\n - DOMAIN-SUFFIX,banners.itweb.co.za,AdBlock\n - DOMAIN-SUFFIX,banners.playocio.com,AdBlock\n - DOMAIN-SUFFIX,bannershotlink.perfectgonzo.com,AdBlock\n - DOMAIN-SUFFIX,baoyatu.cc,AdBlock\n - DOMAIN-SUFFIX,bar.baidu.com,AdBlock\n - DOMAIN-SUFFIX,bartender.cc,AdBlock\n - DOMAIN-SUFFIX,base.filedot.xyz,AdBlock\n - DOMAIN-SUFFIX,bat.bing.com,AdBlock\n - DOMAIN-SUFFIX,bax.xiawu.com,AdBlock\n - DOMAIN-SUFFIX,baxf.m.shuhuangge.org,AdBlock\n - DOMAIN-SUFFIX,bay.xiawu.com,AdBlock\n - DOMAIN-SUFFIX,baycode.cn,AdBlock\n - DOMAIN-SUFFIX,bayimob.com,AdBlock\n - DOMAIN-SUFFIX,bazinga.mse.sogou.com,AdBlock\n - DOMAIN-SUFFIX,bb.tuku.cc,AdBlock\n - DOMAIN-SUFFIX,bb1429.com,AdBlock\n - DOMAIN-SUFFIX,bbcc.yxlady.com,AdBlock\n - DOMAIN-SUFFIX,bbcoe.cn,AdBlock\n - DOMAIN-SUFFIX,bbdm.051661.com,AdBlock\n - DOMAIN-SUFFIX,bbsimages.zkxf119.com,AdBlock\n - DOMAIN-SUFFIX,bc.geocities.yahoo.co.jp,AdBlock\n - DOMAIN-SUFFIX,bccyyc.com,AdBlock\n - DOMAIN-SUFFIX,bcjjg.bugsevent.com,AdBlock\n - DOMAIN-SUFFIX,bcjxf.bugsevent.com,AdBlock\n - DOMAIN-SUFFIX,bd.ershenghuo.com,AdBlock\n - DOMAIN-SUFFIX,bd.gow100.com,AdBlock\n - DOMAIN-SUFFIX,bd.haomagujia.com,AdBlock\n - DOMAIN-SUFFIX,bd.soarfi.cn,AdBlock\n - DOMAIN-SUFFIX,bd.wayqq.cn,AdBlock\n - DOMAIN-SUFFIX,bd01.daqiso.com,AdBlock\n - DOMAIN-SUFFIX,bd1.365qilu.com,AdBlock\n - DOMAIN-SUFFIX,bd1.52che.com,AdBlock\n - DOMAIN-SUFFIX,bd1.fengdu100.com,AdBlock\n - DOMAIN-SUFFIX,bd1.flfgw.cn,AdBlock\n - DOMAIN-SUFFIX,bd1.home8080.cn,AdBlock\n - DOMAIN-SUFFIX,bd1.jobui.com,AdBlock\n - DOMAIN-SUFFIX,bd1.nipic.com,AdBlock\n - DOMAIN-SUFFIX,bd1.nxing.cn,AdBlock\n - DOMAIN-SUFFIX,bd1.pipaw.com,AdBlock\n - DOMAIN-SUFFIX,bd1.szhk.com,AdBlock\n - DOMAIN-SUFFIX,bd1.wowoqq.com,AdBlock\n - DOMAIN-SUFFIX,bd1.xiangha.com,AdBlock\n - DOMAIN-SUFFIX,bd2.52che.com,AdBlock\n - DOMAIN-SUFFIX,bd2.flfgw.cn,AdBlock\n - DOMAIN-SUFFIX,bd2.home8080.cn,AdBlock\n - DOMAIN-SUFFIX,bd2.jobui.com,AdBlock\n - DOMAIN-SUFFIX,bd2.nipic.com,AdBlock\n - DOMAIN-SUFFIX,bd2.pipaw.com,AdBlock\n - DOMAIN-SUFFIX,bd3.chuiyue.com,AdBlock\n - DOMAIN-SUFFIX,bd3.jobui.com,AdBlock\n - DOMAIN-SUFFIX,bd4.chuiyue.com,AdBlock\n - DOMAIN-SUFFIX,bdad.hao224.com,AdBlock\n - DOMAIN-SUFFIX,bdcode.gaosan.com,AdBlock\n - DOMAIN-SUFFIX,bdcode.youke.com,AdBlock\n - DOMAIN-SUFFIX,bdd.hainan.net,AdBlock\n - DOMAIN-SUFFIX,bddm.999d.com,AdBlock\n - DOMAIN-SUFFIX,bdfpb1.8684.com,AdBlock\n - DOMAIN-SUFFIX,bdfpb2.8684.com,AdBlock\n - DOMAIN-SUFFIX,bdjiaoben.wmxa.cn,AdBlock\n - DOMAIN-SUFFIX,bdjs.120askimages.com,AdBlock\n - DOMAIN-SUFFIX,bdjs.6237237.com,AdBlock\n - DOMAIN-SUFFIX,bdjs.99.com.cn,AdBlock\n - DOMAIN-SUFFIX,bdjs.999d.com,AdBlock\n - DOMAIN-SUFFIX,bd-js.baixing.net,AdBlock\n - DOMAIN-SUFFIX,bdjs.faxingzhan.com,AdBlock\n - DOMAIN-SUFFIX,bdjs.itechwall.com,AdBlock\n - DOMAIN-SUFFIX,bdjs.ixiumei.com,AdBlock\n - DOMAIN-SUFFIX,bdjs.jb51.net,AdBlock\n - DOMAIN-SUFFIX,bdjs.kaixin100.com,AdBlock\n - DOMAIN-SUFFIX,bdjs.laonanren.com,AdBlock\n - DOMAIN-SUFFIX,bdjs.ylq.com,AdBlock\n - DOMAIN-SUFFIX,bdjs1.ixiumei.com,AdBlock\n - DOMAIN-SUFFIX,bdlm.120askimages.com,AdBlock\n - DOMAIN-SUFFIX,bdlm1.hc360.com,AdBlock\n - DOMAIN-SUFFIX,bdlncs1.familydoctor.com.cn,AdBlock\n - DOMAIN-SUFFIX,bdmjs.xywy.com,AdBlock\n - DOMAIN-SUFFIX,bdmm.xywy.com,AdBlock\n - DOMAIN-SUFFIX,bdplus.baidu.com,AdBlock\n - DOMAIN-SUFFIX,bdpuaw.com,AdBlock\n - DOMAIN-SUFFIX,bd-s.baixing.net,AdBlock\n - DOMAIN-SUFFIX,bds.hainan.net,AdBlock\n - DOMAIN-SUFFIX,bds.soarfi.cn,AdBlock\n - DOMAIN-SUFFIX,bdtongfei.cn,AdBlock\n - DOMAIN-SUFFIX,bduserlog.eastmoney.com,AdBlock\n - DOMAIN-SUFFIX,beacon.gtimg.com,AdBlock\n - DOMAIN-SUFFIX,beacon.krxd.net,AdBlock\n - DOMAIN-SUFFIX,beacon.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,beacon.tingyun.com,AdBlock\n - DOMAIN-SUFFIX,beacon-us-sjc1.rubiconproject.com,AdBlock\n - DOMAIN-SUFFIX,beap.adss.yahoo.com,AdBlock\n - DOMAIN-SUFFIX,beap-bc.yahoo.com,AdBlock\n - DOMAIN-SUFFIX,bebelait.com,AdBlock\n - DOMAIN-SUFFIX,becode.qiushibaike.com,AdBlock\n - DOMAIN-SUFFIX,beeho.site,AdBlock\n - DOMAIN-SUFFIX,beerto.cn,AdBlock\n - DOMAIN-SUFFIX,beha.ksmobile.com,AdBlock\n - DOMAIN-SUFFIX,behe.com,AdBlock\n - DOMAIN-SUFFIX,beilamusi.com,AdBlock\n - DOMAIN-SUFFIX,beintoo.com,AdBlock\n - DOMAIN-SUFFIX,benshiw.net,AdBlock\n - DOMAIN-SUFFIX,bepolite.eu,AdBlock\n - DOMAIN-SUFFIX,bes-progfree.com,AdBlock\n - DOMAIN-SUFFIX,bet36500050.com,AdBlock\n - DOMAIN-SUFFIX,beta.vpon.com,AdBlock\n - DOMAIN-SUFFIX,betsonsport.ru,AdBlock\n - DOMAIN-SUFFIX,betterzip.net,AdBlock\n - DOMAIN-SUFFIX,bewaycare.com,AdBlock\n - DOMAIN-SUFFIX,beyondcompare.cc,AdBlock\n - DOMAIN-SUFFIX,bfdcdn.com,AdBlock\n - DOMAIN-SUFFIX,bglog.bitauto.com,AdBlock\n - DOMAIN-SUFFIX,bgrndi.com,AdBlock\n - DOMAIN-SUFFIX,bh.contextweb.com,AdBlock\n - DOMAIN-SUFFIX,bhjac.azvub.cn,AdBlock\n - DOMAIN-SUFFIX,bianxianmao.com,AdBlock\n - DOMAIN-SUFFIX,biddingos.com,AdBlock\n - DOMAIN-SUFFIX,biddingx.com,AdBlock\n - DOMAIN-SUFFIX,bidvertiser.com,AdBlock\n - DOMAIN-SUFFIX,bigbos.top,AdBlock\n - DOMAIN-SUFFIX,bigboy.eurogamer.net,AdBlock\n - DOMAIN-SUFFIX,billionfocus.com,AdBlock\n - DOMAIN-SUFFIX,binaryage-leechgate.herokuapp.com,AdBlock\n - DOMAIN-SUFFIX,bingdianhuanyuan.cn,AdBlock\n - DOMAIN-SUFFIX,bingyinq.com,AdBlock\n - DOMAIN-SUFFIX,biq.keefung-zs.com,AdBlock\n - DOMAIN-SUFFIX,bite.theta.sogoucdn.com,AdBlock\n - DOMAIN-SUFFIX,bitsumactivationserver.com,AdBlock\n - DOMAIN-SUFFIX,bivitr.com,AdBlock\n - DOMAIN-SUFFIX,bixia.fymm.cn,AdBlock\n - DOMAIN-SUFFIX,biyibia.com,AdBlock\n - DOMAIN-SUFFIX,biz.gexing.com,AdBlock\n - DOMAIN-SUFFIX,biz.live.xunlei.com,AdBlock\n - DOMAIN-SUFFIX,biz.vpon.com,AdBlock\n - DOMAIN-SUFFIX,biz.weibo.com,AdBlock\n - DOMAIN-SUFFIX,biz37.net,AdBlock\n - DOMAIN-SUFFIX,bizanti.youwatch.org,AdBlock\n - DOMAIN-SUFFIX,bj.imp.voiceads.cn,AdBlock\n - DOMAIN-SUFFIX,bj14.9669.cn,AdBlock\n - DOMAIN-SUFFIX,bjcathay.com,AdBlock\n - DOMAIN-SUFFIX,bjcu.u3.ucweb.com,AdBlock\n - DOMAIN-SUFFIX,bjedpt.com,AdBlock\n - DOMAIN-SUFFIX,bjs.9669.cn,AdBlock\n - DOMAIN-SUFFIX,bkdg.net,AdBlock\n - DOMAIN-SUFFIX,bl.wavecdn.de,AdBlock\n - DOMAIN-SUFFIX,bla.gtimg.com,AdBlock\n - DOMAIN-SUFFIX,blaaaa12.googlecode.com,AdBlock\n - DOMAIN-SUFFIX,blb.winasdaq.com,AdBlock\n - DOMAIN-SUFFIX,bllbaby.cn,AdBlock\n - DOMAIN-SUFFIX,blogad01.myweb.hinet.net,AdBlock\n - DOMAIN-SUFFIX,blogad02.myweb.hinet.net,AdBlock\n - DOMAIN-SUFFIX,bluekai.com,AdBlock\n - DOMAIN-SUFFIX,bluhostedbanners.blucigs.com,AdBlock\n - DOMAIN-SUFFIX,bmg.wnbfw.com,AdBlock\n - DOMAIN-SUFFIX,bmp.ali213.net,AdBlock\n - DOMAIN-SUFFIX,bmp1.ali213.net,AdBlock\n - DOMAIN-SUFFIX,bmw2ep.paomifen.cn,AdBlock\n - DOMAIN-SUFFIX,bnrs.ilm.ee,AdBlock\n - DOMAIN-SUFFIX,boardx.huanqiu.com,AdBlock\n - DOMAIN-SUFFIX,bob.crazyshit.com,AdBlock\n - DOMAIN-SUFFIX,bobo.163.com,AdBlock\n - DOMAIN-SUFFIX,bolt.jebe.renren.com,AdBlock\n - DOMAIN-SUFFIX,borsendental.com,AdBlock\n - DOMAIN-SUFFIX,bosiwangzi.cn,AdBlock\n - DOMAIN-SUFFIX,box.anchorfree.net,AdBlock\n - DOMAIN-SUFFIX,boxercrazy.org,AdBlock\n - DOMAIN-SUFFIX,boxshows.com,AdBlock\n - DOMAIN-SUFFIX,boyxu.cn,AdBlock\n - DOMAIN-SUFFIX,bp.mobad.ijinshan.com,AdBlock\n - DOMAIN-SUFFIX,br.blackfling.com,AdBlock\n - DOMAIN-SUFFIX,br.fling.com,AdBlock\n - DOMAIN-SUFFIX,br.realitykings.com,AdBlock\n - DOMAIN-SUFFIX,brakefluid.website,AdBlock\n - DOMAIN-SUFFIX,brand.sogou.com,AdBlock\n - DOMAIN-SUFFIX,brandshow.58.com,AdBlock\n - DOMAIN-SUFFIX,brcache.madthumbs.com,AdBlock\n - DOMAIN-SUFFIX,breeze.olclient.baofeng.com,AdBlock\n - DOMAIN-SUFFIX,breezily168.com,AdBlock\n - DOMAIN-SUFFIX,brizads.com,AdBlock\n - DOMAIN-SUFFIX,bro.flyme.cn,AdBlock\n - DOMAIN-SUFFIX,bryonypie.com,AdBlock\n - DOMAIN-SUFFIX,bs.5442.com,AdBlock\n - DOMAIN-SUFFIX,bs.serving-sys.com,AdBlock\n - DOMAIN-SUFFIX,bs14.9669.cn,AdBlock\n - DOMAIN-SUFFIX,bsch.serving-sys.com,AdBlock\n - DOMAIN-SUFFIX,bsdev.cn,AdBlock\n - DOMAIN-SUFFIX,bshare.cn,AdBlock\n - DOMAIN-SUFFIX,bshare.optimix.asia,AdBlock\n - DOMAIN-SUFFIX,bsiet.husky.sogou.com,AdBlock\n - DOMAIN-SUFFIX,bss.pandora.xiaomi.com,AdBlock\n - DOMAIN-SUFFIX,bstatic.1kejian.com,AdBlock\n - DOMAIN-SUFFIX,bstatic.diyifanwen.com,AdBlock\n - DOMAIN-SUFFIX,bt.xitongmonitor.com,AdBlock\n - DOMAIN-SUFFIX,bt641499.gotoip4.com,AdBlock\n - DOMAIN-SUFFIX,bthergyuan.com,AdBlock\n - DOMAIN-SUFFIX,btlaunch.baidu.com,AdBlock\n - DOMAIN-SUFFIX,btn.onlylady.com,AdBlock\n - DOMAIN-SUFFIX,btn.pchome.net,AdBlock\n - DOMAIN-SUFFIX,btr.domywife.com,AdBlock\n - DOMAIN-SUFFIX,btrace.qq.com,AdBlock\n - DOMAIN-SUFFIX,bttrack.com,AdBlock\n - DOMAIN-SUFFIX,btyou.com,AdBlock\n - DOMAIN-SUFFIX,bu01.zybang.com,AdBlock\n - DOMAIN-SUFFIX,bu02.zybang.com,AdBlock\n - DOMAIN-SUFFIX,bu1.duba.com,AdBlock\n - DOMAIN-SUFFIX,bu2.duba.com,AdBlock\n - DOMAIN-SUFFIX,bugtags.com,AdBlock\n - DOMAIN-SUFFIX,business.92wy.com,AdBlock\n - DOMAIN-SUFFIX,business.inveno.com,AdBlock\n - DOMAIN-SUFFIX,buyimg.bianxianmao.com,AdBlock\n - DOMAIN-SUFFIX,buysellads.com,AdBlock\n - DOMAIN-SUFFIX,buyu8001.com,AdBlock\n - DOMAIN-SUFFIX,bwp.theinsider.com.com,AdBlock\n - DOMAIN-SUFFIX,bx.optimix.asia,AdBlock\n - DOMAIN-SUFFIX,bx01.optimix.asia,AdBlock\n - DOMAIN-SUFFIX,bxgmb.com,AdBlock\n - DOMAIN-SUFFIX,bxjpl.cn,AdBlock\n - DOMAIN-SUFFIX,by.dm5.com,AdBlock\n - DOMAIN-SUFFIX,by.mbai.cn,AdBlock\n - DOMAIN-SUFFIX,by.tel.cdndm.com,AdBlock\n - DOMAIN-SUFFIX,by8974.com,AdBlock\n - DOMAIN-SUFFIX,bydonline.com,AdBlock\n - DOMAIN-SUFFIX,bypbwm.cn,AdBlock\n - DOMAIN-SUFFIX,c.0.0.0.0.cn,AdBlock\n - DOMAIN-SUFFIX,c.28487.net,AdBlock\n - DOMAIN-SUFFIX,c.35kds.com,AdBlock\n - DOMAIN-SUFFIX,c.365yigou.cn,AdBlock\n - DOMAIN-SUFFIX,c.45io.com,AdBlock\n - DOMAIN-SUFFIX,c.51y5.net,AdBlock\n - DOMAIN-SUFFIX,c.adbxb.cn,AdBlock\n - DOMAIN-SUFFIX,c.anmeilai.net,AdBlock\n - DOMAIN-SUFFIX,c.baidu.com,AdBlock\n - DOMAIN-SUFFIX,c.betrad.com,AdBlock\n - DOMAIN-SUFFIX,c.bigmir.net,AdBlock\n - DOMAIN-SUFFIX,c.bing.com,AdBlock\n - DOMAIN-SUFFIX,c.bxb.oupeng.com,AdBlock\n - DOMAIN-SUFFIX,c.codeonclick.com,AdBlock\n - DOMAIN-SUFFIX,c.cyhx98.com,AdBlock\n - DOMAIN-SUFFIX,c.cyto-biotherapy.com,AdBlock\n - DOMAIN-SUFFIX,c.danangmo.cn,AdBlock\n - DOMAIN-SUFFIX,c.data.mob.com,AdBlock\n - DOMAIN-SUFFIX,c.dokrmob.com,AdBlock\n - DOMAIN-SUFFIX,c.dzytjqcc.com,AdBlock\n - DOMAIN-SUFFIX,c.effectivemeasure.net,AdBlock\n - DOMAIN-SUFFIX,c.f1zd.com,AdBlock\n - DOMAIN-SUFFIX,c.gj.qq.com,AdBlock\n - DOMAIN-SUFFIX,c.guangtui1999.com,AdBlock\n - DOMAIN-SUFFIX,c.gzsanxiaomingshi.cn,AdBlock\n - DOMAIN-SUFFIX,c.idasui.cn,AdBlock\n - DOMAIN-SUFFIX,c.iogous.com,AdBlock\n - DOMAIN-SUFFIX,c.k429fma.com,AdBlock\n - DOMAIN-SUFFIX,c.kbf365.cn,AdBlock\n - DOMAIN-SUFFIX,c.kl6636.net,AdBlock\n - DOMAIN-SUFFIX,c.kuwo.cn,AdBlock\n - DOMAIN-SUFFIX,c.lianwangtech.com,AdBlock\n - DOMAIN-SUFFIX,c.live.com,AdBlock\n - DOMAIN-SUFFIX,c.lucktui.com,AdBlock\n - DOMAIN-SUFFIX,c.metrigo.com,AdBlock\n - DOMAIN-SUFFIX,c.mightiger.net,AdBlock\n - DOMAIN-SUFFIX,c.minisplat.cn,AdBlock\n - DOMAIN-SUFFIX,c.mkmp365.com,AdBlock\n - DOMAIN-SUFFIX,c.mnjkw.cn,AdBlock\n - DOMAIN-SUFFIX,c.mobishu.com,AdBlock\n - DOMAIN-SUFFIX,c.msn.com,AdBlock\n - DOMAIN-SUFFIX,c.msn.com.cn,AdBlock\n - DOMAIN-SUFFIX,c.netu.tv,AdBlock\n - DOMAIN-SUFFIX,c.ningbojipiao.com,AdBlock\n - DOMAIN-SUFFIX,c.ns8d.com,AdBlock\n - DOMAIN-SUFFIX,c.okmgy.cn,AdBlock\n - DOMAIN-SUFFIX,c.panqis.cn,AdBlock\n - DOMAIN-SUFFIX,c.panqishu.com,AdBlock\n - DOMAIN-SUFFIX,c.piliangzhuce.cn,AdBlock\n - DOMAIN-SUFFIX,c.ptffw.net,AdBlock\n - DOMAIN-SUFFIX,c.queene.cn,AdBlock\n - DOMAIN-SUFFIX,c.rexuebi.com,AdBlock\n - DOMAIN-SUFFIX,c.rscxwmj.cn,AdBlock\n - DOMAIN-SUFFIX,c.shunlige.com,AdBlock\n - DOMAIN-SUFFIX,c.silvinst.com,AdBlock\n - DOMAIN-SUFFIX,c.sss1989.com,AdBlock\n - DOMAIN-SUFFIX,c.sssgao999.com,AdBlock\n - DOMAIN-SUFFIX,c.start280.com,AdBlock\n - DOMAIN-SUFFIX,c.statcounter.com,AdBlock\n - DOMAIN-SUFFIX,c.statstat888.com,AdBlock\n - DOMAIN-SUFFIX,c.sy123888.com,AdBlock\n - DOMAIN-SUFFIX,c.t98u8f.com,AdBlock\n - DOMAIN-SUFFIX,c.tctyb.cn,AdBlock\n - DOMAIN-SUFFIX,c.v4dwkcv.com,AdBlock\n - DOMAIN-SUFFIX,c.vip97.net,AdBlock\n - DOMAIN-SUFFIX,c.wechat.jx.cn,AdBlock\n - DOMAIN-SUFFIX,c.wkanx.com,AdBlock\n - DOMAIN-SUFFIX,c.wrating.com,AdBlock\n - DOMAIN-SUFFIX,c.xianguonongchang.org,AdBlock\n - DOMAIN-SUFFIX,c.xznykf.org,AdBlock\n - DOMAIN-SUFFIX,c.ylist.cn,AdBlock\n - DOMAIN-SUFFIX,c.ynlysg.com,AdBlock\n - DOMAIN-SUFFIX,c.youdao.com,AdBlock\n - DOMAIN-SUFFIX,c.zgnm.cc,AdBlock\n - DOMAIN-SUFFIX,c.zlongad.com,AdBlock\n - DOMAIN-SUFFIX,c.zmjuan.org,AdBlock\n - DOMAIN-SUFFIX,c.zxyywdj.org,AdBlock\n - DOMAIN-SUFFIX,c0.ifengimg.com,AdBlock\n - DOMAIN-SUFFIX,c03.optimix.asia,AdBlock\n - DOMAIN-SUFFIX,c0563.com,AdBlock\n - DOMAIN-SUFFIX,c0594.com,AdBlock\n - DOMAIN-SUFFIX,c0i8h8ac7e.bid,AdBlock\n - DOMAIN-SUFFIX,c1.4qx.net,AdBlock\n - DOMAIN-SUFFIX,c1.668559.com,AdBlock\n - DOMAIN-SUFFIX,c1.ifengimg.com,AdBlock\n - DOMAIN-SUFFIX,c1.keyrun.cn,AdBlock\n - DOMAIN-SUFFIX,c1.lianwangtech.com,AdBlock\n - DOMAIN-SUFFIX,c1.minisplat.cn,AdBlock\n - DOMAIN-SUFFIX,c1.popads.net,AdBlock\n - DOMAIN-SUFFIX,c1.statcounter.com,AdBlock\n - DOMAIN-SUFFIX,c1.ulink.cc,AdBlock\n - DOMAIN-SUFFIX,c1.wkanx.com,AdBlock\n - DOMAIN-SUFFIX,c1.xcy8.com,AdBlock\n - DOMAIN-SUFFIX,c16cp358.com,AdBlock\n - DOMAIN-SUFFIX,c2.58toto.net,AdBlock\n - DOMAIN-SUFFIX,c2.popads.net,AdBlock\n - DOMAIN-SUFFIX,c2.statcounter.com,AdBlock\n - DOMAIN-SUFFIX,c3.gostats.cn,AdBlock\n - DOMAIN-SUFFIX,c3.moogos.com,AdBlock\n - DOMAIN-SUFFIX,c6.bjdianyue.com,AdBlock\n - DOMAIN-SUFFIX,c6.lnymd.com,AdBlock\n - DOMAIN-SUFFIX,c77777777.com,AdBlock\n - DOMAIN-SUFFIX,c8.wangdq.com,AdBlock\n - DOMAIN-SUFFIX,c8b.jcdb88.com,AdBlock\n - DOMAIN-SUFFIX,ca.5173car.com,AdBlock\n - DOMAIN-SUFFIX,ca.w8.com.cn,AdBlock\n - DOMAIN-SUFFIX,caamei.com,AdBlock\n - DOMAIN-SUFFIX,cacaca.0571yy.com,AdBlock\n - DOMAIN-SUFFIX,cacaca.sp96878.com,AdBlock\n - DOMAIN-SUFFIX,cacafly.net,AdBlock\n - DOMAIN-SUFFIX,cache.betweendigital.com,AdBlock\n - DOMAIN-SUFFIX,cache.soloth.com,AdBlock\n - DOMAIN-SUFFIX,cache.xw126.com,AdBlock\n - DOMAIN-SUFFIX,cachead.com,AdBlock\n - DOMAIN-SUFFIX,cachenotice.cp11.ott.cibntv.net,AdBlock\n - DOMAIN-SUFFIX,cachesit.com,AdBlock\n - DOMAIN-SUFFIX,cache-ssl.celtra.com,AdBlock\n - DOMAIN-SUFFIX,cad.chosun.com,AdBlock\n - DOMAIN-SUFFIX,c-adash.m.taobao.com,AdBlock\n - DOMAIN-SUFFIX,cadvv.heraldm.com,AdBlock\n - DOMAIN-SUFFIX,cadvv.koreaherald.com,AdBlock\n - DOMAIN-SUFFIX,caiyifz.com,AdBlock\n - DOMAIN-SUFFIX,cal.meizu.com,AdBlock\n - DOMAIN-SUFFIX,caliyuna.cn,AdBlock\n - DOMAIN-SUFFIX,calopenupdate.comm.miui.com,AdBlock\n - DOMAIN-SUFFIX,cams.pornrabbit.com,AdBlock\n - DOMAIN-SUFFIX,cangnews.com,AdBlock\n - DOMAIN-SUFFIX,canvas.thenextweb.com,AdBlock\n - DOMAIN-SUFFIX,caob5.info,AdBlock\n - DOMAIN-SUFFIX,caolvch.com,AdBlock\n - DOMAIN-SUFFIX,cap.cyberlink.com,AdBlock\n - DOMAIN-SUFFIX,cap.touclick.com,AdBlock\n - DOMAIN-SUFFIX,car.mobadme.jp,AdBlock\n - DOMAIN-SUFFIX,carbonads.net,AdBlock\n - DOMAIN-SUFFIX,cas.clickability.com,AdBlock\n - DOMAIN-SUFFIX,cas.criteo.com,AdBlock\n - DOMAIN-SUFFIX,casalemedia.com,AdBlock\n - DOMAIN-SUFFIX,casee.cn,AdBlock\n - DOMAIN-SUFFIX,cash.neweramediaworks.com,AdBlock\n - DOMAIN-SUFFIX,cast.innity.com,AdBlock\n - DOMAIN-SUFFIX,cast.ra.icast.cn,AdBlock\n - DOMAIN-SUFFIX,cast-bid27-j.adtdp.com,AdBlock\n - DOMAIN-SUFFIX,castplatform.com,AdBlock\n - DOMAIN-SUFFIX,catalog.video.msn.com,AdBlock\n - DOMAIN-SUFFIX,catch.gift,AdBlock\n - DOMAIN-SUFFIX,cayanfang.com,AdBlock\n - DOMAIN-SUFFIX,cb.baidu.com,AdBlock\n - DOMAIN-SUFFIX,cb.h5.coffeedak.cn,AdBlock\n - DOMAIN-SUFFIX,cbjs.baidu.com,AdBlock\n - DOMAIN-SUFFIX,cbs.wondershare.com,AdBlock\n - DOMAIN-SUFFIX,cc.0133hao.net,AdBlock\n - DOMAIN-SUFFIX,cc.1515788.net,AdBlock\n - DOMAIN-SUFFIX,cc.365yigou.cn,AdBlock\n - DOMAIN-SUFFIX,cc.700ok.net,AdBlock\n - DOMAIN-SUFFIX,cc.dace.hupu.com,AdBlock\n - DOMAIN-SUFFIX,cc.idasui.cn,AdBlock\n - DOMAIN-SUFFIX,cc.moquanad.com,AdBlock\n - DOMAIN-SUFFIX,cc.piao.jianzhigg.com,AdBlock\n - DOMAIN-SUFFIX,cc.st123.info,AdBlock\n - DOMAIN-SUFFIX,cc.xtgreat.com,AdBlock\n - DOMAIN-SUFFIX,cc.yac8.com,AdBlock\n - DOMAIN-SUFFIX,cca.mob.com,AdBlock\n - DOMAIN-SUFFIX,ccb.uncle-ad.com,AdBlock\n - DOMAIN-SUFFIX,ccbaihehq.com,AdBlock\n - DOMAIN-SUFFIX,cccrir.com,AdBlock\n - DOMAIN-SUFFIX,ccr.yxdown.com,AdBlock\n - DOMAIN-SUFFIX,cctyly.com,AdBlock\n - DOMAIN-SUFFIX,cd.bendibao.com,AdBlock\n - DOMAIN-SUFFIX,cdgxq.com,AdBlock\n - DOMAIN-SUFFIX,cdhoc.piyaji.cn,AdBlock\n - DOMAIN-SUFFIX,cdn.0i-i0.com,AdBlock\n - DOMAIN-SUFFIX,cdn.5bong.com,AdBlock\n - DOMAIN-SUFFIX,cdn.adsk2.co,AdBlock\n - DOMAIN-SUFFIX,cdn.adstract.com,AdBlock\n - DOMAIN-SUFFIX,cdn.aegins.com,AdBlock\n - DOMAIN-SUFFIX,cdn.aiclicash.com,AdBlock\n - DOMAIN-SUFFIX,cdn.app.kachapt.cn,AdBlock\n - DOMAIN-SUFFIX,cdn.app.liuxingyul.cn,AdBlock\n - DOMAIN-SUFFIX,cdn.at.atwola.com,AdBlock\n - DOMAIN-SUFFIX,cdn.atwola.com,AdBlock\n - DOMAIN-SUFFIX,cdn.cooguo.com,AdBlock\n - DOMAIN-SUFFIX,cdn.districtm.io,AdBlock\n - DOMAIN-SUFFIX,cdn.dragonstatic.com,AdBlock\n - DOMAIN-SUFFIX,cdn.dsp.com,AdBlock\n - DOMAIN-SUFFIX,cdn.earnify.com,AdBlock\n - DOMAIN-SUFFIX,cdn.fastclick.net,AdBlock\n - DOMAIN-SUFFIX,cdn.hivps.xyz,AdBlock\n - DOMAIN-SUFFIX,cdn.hyperpromote.com,AdBlock\n - DOMAIN-SUFFIX,cdn.iclicash.com,AdBlock\n - DOMAIN-SUFFIX,cdn.img.kachapt.cn,AdBlock\n - DOMAIN-SUFFIX,cdn.img.liuxingyul.cn,AdBlock\n - DOMAIN-SUFFIX,cdn.innity.net,AdBlock\n - DOMAIN-SUFFIX,cdn.jesgoo.com,AdBlock\n - DOMAIN-SUFFIX,cdn.jiuzhilan.com,AdBlock\n - DOMAIN-SUFFIX,cdn.jllstudio.com,AdBlock\n - DOMAIN-SUFFIX,cdn.komentary.aol.com,AdBlock\n - DOMAIN-SUFFIX,cdn.krxd.net,AdBlock\n - DOMAIN-SUFFIX,cdn.lu.sogoucdn.com,AdBlock\n - DOMAIN-SUFFIX,cdn.marketgid.com,AdBlock\n - DOMAIN-SUFFIX,cdn.mdotm.com,AdBlock\n - DOMAIN-SUFFIX,cdn.media.innity.net,AdBlock\n - DOMAIN-SUFFIX,cdn.millennialmedia.com,AdBlock\n - DOMAIN-SUFFIX,cdn.mingmingtehui.com,AdBlock\n - DOMAIN-SUFFIX,cdn.moji.com,AdBlock\n - DOMAIN-SUFFIX,cdn.moji002.com,AdBlock\n - DOMAIN-SUFFIX,cdn.moogos.com,AdBlock\n - DOMAIN-SUFFIX,cdn.ndapp.com,AdBlock\n - DOMAIN-SUFFIX,cdn.newapi.com,AdBlock\n - DOMAIN-SUFFIX,cdn.optaim.com,AdBlock\n - DOMAIN-SUFFIX,cdn.outfit7.com,AdBlock\n - DOMAIN-SUFFIX,cdn.popcash.net,AdBlock\n - DOMAIN-SUFFIX,cdn.popmyads.com,AdBlock\n - DOMAIN-SUFFIX,cdn.puata.info,AdBlock\n - DOMAIN-SUFFIX,cdn.scdng.com,AdBlock\n - DOMAIN-SUFFIX,cdn.sp.rizhao9.com,AdBlock\n - DOMAIN-SUFFIX,cdn.tianmidian.com,AdBlock\n - DOMAIN-SUFFIX,cdn.tinglian.com,AdBlock\n - DOMAIN-SUFFIX,cdn.vamaker.com,AdBlock\n - DOMAIN-SUFFIX,cdn.viglink.com,AdBlock\n - DOMAIN-SUFFIX,cdn.xianliao.me,AdBlock\n - DOMAIN-SUFFIX,cdn.zampda.net,AdBlock\n - DOMAIN-SUFFIX,cdn0.mobmore.com,AdBlock\n - DOMAIN-SUFFIX,cdn1.lbesec.com,AdBlock\n - DOMAIN-SUFFIX,cdn1.res.nx5.com,AdBlock\n - DOMAIN-SUFFIX,cdn1.res.uzham.com,AdBlock\n - DOMAIN-SUFFIX,cdn1.srv.revdepo.com,AdBlock\n - DOMAIN-SUFFIX,cdn2.moji002.com,AdBlock\n - DOMAIN-SUFFIX,cdnads.com,AdBlock\n - DOMAIN-SUFFIX,cdn-ads.oss-cn-shanghai.aliyuncs.com,AdBlock\n - DOMAIN-SUFFIX,cdnas.hyperpromote.com,AdBlock\n - DOMAIN-SUFFIX,cdn-gcs.outfit7.com,AdBlock\n - DOMAIN-SUFFIX,cdnimg.liehu.ijinshan.com,AdBlock\n - DOMAIN-SUFFIX,cdnis.hyperpromote.com,AdBlock\n - DOMAIN-SUFFIX,cdnmaster.com,AdBlock\n - DOMAIN-SUFFIX,cdnny.com,AdBlock\n - DOMAIN-SUFFIX,cdnpa.hyperpromote.com,AdBlock\n - DOMAIN-SUFFIX,cdn-rtb.sape.ru,AdBlock\n - DOMAIN-SUFFIX,cdn-settings.segment.com,AdBlock\n - DOMAIN-SUFFIX,cdntest.a8tiyu.com,AdBlock\n - DOMAIN-SUFFIX,cds.51y5.net,AdBlock\n - DOMAIN-SUFFIX,cdyqc.com,AdBlock\n - DOMAIN-SUFFIX,ced.sascdn.com,AdBlock\n - DOMAIN-SUFFIX,cee1.iteye.com,AdBlock\n - DOMAIN-SUFFIX,cee2.iteye.com,AdBlock\n - DOMAIN-SUFFIX,cerebral.typn.com,AdBlock\n - DOMAIN-SUFFIX,cfdanet.com,AdBlock\n - DOMAIN-SUFFIX,cferw.com,AdBlock\n - DOMAIN-SUFFIX,cfg-md.gridsumdissector.com,AdBlock\n - DOMAIN-SUFFIX,cfg-vd.gridsumdissector.com,AdBlock\n - DOMAIN-SUFFIX,cgskqg.com,AdBlock\n - DOMAIN-SUFFIX,chadegongxiao.com,AdBlock\n - DOMAIN-SUFFIX,chance-ad.com,AdBlock\n - DOMAIN-SUFFIX,chanet.com.cn,AdBlock\n - DOMAIN-SUFFIX,changan.bama555.com,AdBlock\n - DOMAIN-SUFFIX,changhehengqi.com,AdBlock\n - DOMAIN-SUFFIX,channel.fanxing.kugou.com,AdBlock\n - DOMAIN-SUFFIX,channeladvisor.com,AdBlock\n - DOMAIN-SUFFIX,chaojilamei.cn,AdBlock\n - DOMAIN-SUFFIX,chaoliangyun.com,AdBlock\n - DOMAIN-SUFFIX,chartbeat.com,AdBlock\n - DOMAIN-SUFFIX,chartboost.com,AdBlock\n - DOMAIN-SUFFIX,chebse.com,AdBlock\n - DOMAIN-SUFFIX,chemdraw.com,AdBlock\n - DOMAIN-SUFFIX,chemdraw.com.cn,AdBlock\n - DOMAIN-SUFFIX,chengadx.com,AdBlock\n - DOMAIN-SUFFIX,chenggao.cn,AdBlock\n - DOMAIN-SUFFIX,chengzhao95511.com,AdBlock\n - DOMAIN-SUFFIX,chenwen7788.com,AdBlock\n - DOMAIN-SUFFIX,chicken18.com,AdBlock\n - DOMAIN-SUFFIX,chidir.com,AdBlock\n - DOMAIN-SUFFIX,chinacsky.com,AdBlock\n - DOMAIN-SUFFIX,chinaheh.com,AdBlock\n - DOMAIN-SUFFIX,chinaliftoff.io,AdBlock\n - DOMAIN-SUFFIX,chinauma.net,AdBlock\n - DOMAIN-SUFFIX,chinaweichu.net,AdBlock\n - DOMAIN-SUFFIX,chjxzk.1555110.cn,AdBlock\n - DOMAIN-SUFFIX,chmae.com,AdBlock\n - DOMAIN-SUFFIX,chnhty.com,AdBlock\n - DOMAIN-SUFFIX,chuantu.biz,AdBlock\n - DOMAIN-SUFFIX,chushoushijian.cn,AdBlock\n - DOMAIN-SUFFIX,ci.csefaazc.net,AdBlock\n - DOMAIN-SUFFIX,ciajingman.com,AdBlock\n - DOMAIN-SUFFIX,cilidaquan.pw,AdBlock\n - DOMAIN-SUFFIX,cindy17club.com,AdBlock\n - DOMAIN-SUFFIX,cip6.czpush.com,AdBlock\n - DOMAIN-SUFFIX,cishantao.com,AdBlock\n - DOMAIN-SUFFIX,ciyitan.com,AdBlock\n - DOMAIN-SUFFIX,cj.qidian.com,AdBlock\n - DOMAIN-SUFFIX,cjhq.baidu.com,AdBlock\n - DOMAIN-SUFFIX,cjmakeding.com,AdBlock\n - DOMAIN-SUFFIX,cjmkt.com,AdBlock\n - DOMAIN-SUFFIX,cjmooter.xcache.kinxcdn.com,AdBlock\n - DOMAIN-SUFFIX,cjroq.bealge.sogou.com,AdBlock\n - DOMAIN-SUFFIX,ck.houyi.baofeng.net,AdBlock\n - DOMAIN-SUFFIX,ck.kejet.net,AdBlock\n - DOMAIN-SUFFIX,cl.he9630.com,AdBlock\n - DOMAIN-SUFFIX,cl.webterren.com,AdBlock\n - DOMAIN-SUFFIX,cl.xzqxzs.com,AdBlock\n - DOMAIN-SUFFIX,cl0.webterren.com,AdBlock\n - DOMAIN-SUFFIX,cl2.webterren.com,AdBlock\n - DOMAIN-SUFFIX,cl3.webterren.com,AdBlock\n - DOMAIN-SUFFIX,cl4.webterren.com,AdBlock\n - DOMAIN-SUFFIX,cl5.webterren.com,AdBlock\n - DOMAIN-SUFFIX,clarity.abacast.com,AdBlock\n - DOMAIN-SUFFIX,cleaner.baidu.com,AdBlock\n - DOMAIN-SUFFIX,click1n.soufun.com,AdBlock\n - DOMAIN-SUFFIX,clickadu.com,AdBlock\n - DOMAIN-SUFFIX,click-cn.plista.com,AdBlock\n - DOMAIN-SUFFIX,clicki.cn,AdBlock\n - DOMAIN-SUFFIX,clicklog.moviebox.baofeng.net,AdBlock\n - DOMAIN-SUFFIX,clickm.fang.com,AdBlock\n - DOMAIN-SUFFIX,clickn.fang.com,AdBlock\n - DOMAIN-SUFFIX,clicks.beap.bc.yahoo.com,AdBlock\n - DOMAIN-SUFFIX,clicks.superpages.com,AdBlock\n - DOMAIN-SUFFIX,clickstrip.6wav.es,AdBlock\n - DOMAIN-SUFFIX,clicktracks.com,AdBlock\n - DOMAIN-SUFFIX,clickzs.com,AdBlock\n - DOMAIN-SUFFIX,client.88tours.com,AdBlock\n - DOMAIN-SUFFIX,client.sidesearch.lycos.com,AdBlock\n - DOMAIN-SUFFIX,client.stats.yinyuetai.com,AdBlock\n - DOMAIN-SUFFIX,client.tenddata.com,AdBlock\n - DOMAIN-SUFFIX,client-api.ele.me,AdBlock\n - DOMAIN-SUFFIX,client-dmp.suishenyun.cn,AdBlock\n - DOMAIN-SUFFIX,cliushow.com,AdBlock\n - DOMAIN-SUFFIX,clk.dxpmedia.com,AdBlock\n - DOMAIN-SUFFIX,clk.gentags.net,AdBlock\n - DOMAIN-SUFFIX,clk.madserving.com,AdBlock\n - DOMAIN-SUFFIX,clk.optaim.com,AdBlock\n - DOMAIN-SUFFIX,clk.pdb.madserving.com,AdBlock\n - DOMAIN-SUFFIX,clk.taptica.com,AdBlock\n - DOMAIN-SUFFIX,clk.uunt.com,AdBlock\n - DOMAIN-SUFFIX,clkads.com,AdBlock\n - DOMAIN-SUFFIX,clkrev.com,AdBlock\n - DOMAIN-SUFFIX,clkservice.mail.youdao.com,AdBlock\n - DOMAIN-SUFFIX,clkservice.union.youdao.com,AdBlock\n - DOMAIN-SUFFIX,clkservice.youdao.com,AdBlock\n - DOMAIN-SUFFIX,clkservice2.dict.youdao.com,AdBlock\n - DOMAIN-SUFFIX,cloud.codenow.cn,AdBlock\n - DOMAIN-SUFFIX,cloud.rovio.com,AdBlock\n - DOMAIN-SUFFIX,cloud.zyiis.net,AdBlock\n - DOMAIN-SUFFIX,cloudad.asia,AdBlock\n - DOMAIN-SUFFIX,cloudcdn.yousee.com,AdBlock\n - DOMAIN-SUFFIX,cloudmobi.net,AdBlock\n - DOMAIN-SUFFIX,cm.adgrx.com,AdBlock\n - DOMAIN-SUFFIX,cm.baidu.com,AdBlock\n - DOMAIN-SUFFIX,cm.ctnsnet.com,AdBlock\n - DOMAIN-SUFFIX,cm.eyereturn.com,AdBlock\n - DOMAIN-SUFFIX,cm.mct01.com,AdBlock\n - DOMAIN-SUFFIX,cm.netseer.com,AdBlock\n - DOMAIN-SUFFIX,cm.p4p.cn.yahoo.com,AdBlock\n - DOMAIN-SUFFIX,cm8.lycos.com,AdBlock\n - DOMAIN-SUFFIX,cmarket.kejet.net,AdBlock\n - DOMAIN-SUFFIX,cmaxisolation.com,AdBlock\n - DOMAIN-SUFFIX,cmcdl.cmcm.com,AdBlock\n - DOMAIN-SUFFIX,cmcore.com,AdBlock\n - DOMAIN-SUFFIX,cmm.xmfish.com,AdBlock\n - DOMAIN-SUFFIX,cmp288.com,AdBlock\n - DOMAIN-SUFFIX,cmpp.gentags.net,AdBlock\n - DOMAIN-SUFFIX,cms.an.m.liebao.cn,AdBlock\n - DOMAIN-SUFFIX,cms.quantserve.com,AdBlock\n - DOMAIN-SUFFIX,cmsapi.wifi8.com,AdBlock\n - DOMAIN-SUFFIX,cmshow.gtimg.cn,AdBlock\n - DOMAIN-SUFFIX,cmslayue.com,AdBlock\n - DOMAIN-SUFFIX,cn.pub.vpon.com,AdBlock\n - DOMAIN-SUFFIX,cn.tatami-solutions.com,AdBlock\n - DOMAIN-SUFFIX,cnbole.net,AdBlock\n - DOMAIN-SUFFIX,cncy8.com,AdBlock\n - DOMAIN-SUFFIX,cndjs-1251973891.coshk.myqcloud.com,AdBlock\n - DOMAIN-SUFFIX,cnetdirectintl.com,AdBlock\n - DOMAIN-SUFFIX,cnetwidget.creativemark.co.uk,AdBlock\n - DOMAIN-SUFFIX,cnfanglei.com,AdBlock\n - DOMAIN-SUFFIX,cnhbxx.com,AdBlock\n - DOMAIN-SUFFIX,cnkok.com,AdBlock\n - DOMAIN-SUFFIX,cnn.dyn.cnn.com,AdBlock\n - DOMAIN-SUFFIX,cnnic.cn,AdBlock\n - DOMAIN-SUFFIX,cnnic.net,AdBlock\n - DOMAIN-SUFFIX,cnnic.net.cn,AdBlock\n - DOMAIN-SUFFIX,cnpinzhuo.com,AdBlock\n - DOMAIN-SUFFIX,cnscdj.com,AdBlock\n - DOMAIN-SUFFIX,cnsjx.net,AdBlock\n - DOMAIN-SUFFIX,cnxad.com,AdBlock\n - DOMAIN-SUFFIX,cnxad.net,AdBlock\n - DOMAIN-SUFFIX,cnzhqs.com,AdBlock\n - DOMAIN-SUFFIX,cnzz.cn,AdBlock\n - DOMAIN-SUFFIX,cnzz.com,AdBlock\n - DOMAIN-SUFFIX,co.dtech.baofeng.com,AdBlock\n - DOMAIN-SUFFIX,cocounion.com,AdBlock\n - DOMAIN-SUFFIX,cod.southmoney.com,AdBlock\n - DOMAIN-SUFFIX,code.3shangyou.com,AdBlock\n - DOMAIN-SUFFIX,code.fastclick.net,AdBlock\n - DOMAIN-SUFFIX,code.hajuwang.cn,AdBlock\n - DOMAIN-SUFFIX,code.hot-mob.com,AdBlock\n - DOMAIN-SUFFIX,code.kaixinjiehun.com,AdBlock\n - DOMAIN-SUFFIX,code.kejet.com,AdBlock\n - DOMAIN-SUFFIX,code.laojiayoufang.com,AdBlock\n - DOMAIN-SUFFIX,code.ttpaper.com,AdBlock\n - DOMAIN-SUFFIX,code.wantaico.com,AdBlock\n - DOMAIN-SUFFIX,code11.onetad.com,AdBlock\n - DOMAIN-SUFFIX,code12.onetad.com,AdBlock\n - DOMAIN-SUFFIX,code1f.m.shushu8.com,AdBlock\n - DOMAIN-SUFFIX,code1fa.m.shushu8.com,AdBlock\n - DOMAIN-SUFFIX,code222.com,AdBlock\n - DOMAIN-SUFFIX,code668.com,AdBlock\n - DOMAIN-SUFFIX,codenow.cn,AdBlock\n - DOMAIN-SUFFIX,codesoftchina.com,AdBlock\n - DOMAIN-SUFFIX,coinblind.com,AdBlock\n - DOMAIN-SUFFIX,coinerra.com,AdBlock\n - DOMAIN-SUFFIX,coin-have.com,AdBlock\n - DOMAIN-SUFFIX,coinhive.com,AdBlock\n - DOMAIN-SUFFIX,coin-hive.com,AdBlock\n - DOMAIN-SUFFIX,coinhive-manager.com,AdBlock\n - DOMAIN-SUFFIX,coin-hive-proxy-ybydcnjgkl.now.sh,AdBlock\n - DOMAIN-SUFFIX,coinminerz.com,AdBlock\n - DOMAIN-SUFFIX,coinnebula.com,AdBlock\n - DOMAIN-SUFFIX,col.hztags.net,AdBlock\n - DOMAIN-SUFFIX,col.pagechoice.net,AdBlock\n - DOMAIN-SUFFIX,collector.githubapp.com,AdBlock\n - DOMAIN-SUFFIX,collector.viki.io,AdBlock\n - DOMAIN-SUFFIX,collector.wasu.cn,AdBlock\n - DOMAIN-SUFFIX,combine.urbanairship.com,AdBlock\n - DOMAIN-SUFFIX,com-eonsun-owl.oss-cn-hangzhou.aliyuncs.com,AdBlock\n - DOMAIN-SUFFIX,com-eonsun-owl-user.oss-cn-hangzhou.aliyuncs.com,AdBlock\n - DOMAIN-SUFFIX,comesgo.com,AdBlock\n - DOMAIN-SUFFIX,comet.yahoo.com,AdBlock\n - DOMAIN-SUFFIX,conf.funshion.com,AdBlock\n - DOMAIN-SUFFIX,conf.vidown.cn,AdBlock\n - DOMAIN-SUFFIX,conf.xiniuz.com,AdBlock\n - DOMAIN-SUFFIX,config.baofeng.net,AdBlock\n - DOMAIN-SUFFIX,config.cocounion.com,AdBlock\n - DOMAIN-SUFFIX,config.ioam.de,AdBlock\n - DOMAIN-SUFFIX,config.kuyun.com,AdBlock\n - DOMAIN-SUFFIX,config.mobisage.cn,AdBlock\n - DOMAIN-SUFFIX,config.push.sogou.com,AdBlock\n - DOMAIN-SUFFIX,config.unityads.unity3d.com,AdBlock\n - DOMAIN-SUFFIX,config2.mparticle.com,AdBlock\n - DOMAIN-SUFFIX,connect.summit.co.uk,AdBlock\n - DOMAIN-SUFFIX,content.livesportmedia.eu,AdBlock\n - DOMAIN-SUFFIX,content.s8bbs.com,AdBlock\n - DOMAIN-SUFFIX,content.streamplay.to,AdBlock\n - DOMAIN-SUFFIX,contentabc.com,AdBlock\n - DOMAIN-SUFFIX,contentrecommend-out.mobile.sina.cn,AdBlock\n - DOMAIN-SUFFIX,conv.youdao.com,AdBlock\n - DOMAIN-SUFFIX,conversion.pro.cn,AdBlock\n - DOMAIN-SUFFIX,conviva.com,AdBlock\n - DOMAIN-SUFFIX,cooguo.com,AdBlock\n - DOMAIN-SUFFIX,cookiemapping.wrating.com,AdBlock\n - DOMAIN-SUFFIX,coolguang.com,AdBlock\n - DOMAIN-SUFFIX,coolnay.com,AdBlock\n - DOMAIN-SUFFIX,cooolyi.cn,AdBlock\n - DOMAIN-SUFFIX,cooolyi.com,AdBlock\n - DOMAIN-SUFFIX,coop.pop.baofeng.com,AdBlock\n - DOMAIN-SUFFIX,cootek-dialer-download.oss-cn-hangzhou.aliyuncs.com,AdBlock\n - DOMAIN-SUFFIX,cootek-file.cdn.cootekservice.com,AdBlock\n - DOMAIN-SUFFIX,cop.my,AdBlock\n - DOMAIN-SUFFIX,coreldrawchina.com,AdBlock\n - DOMAIN-SUFFIX,coremetrics.com,AdBlock\n - DOMAIN-SUFFIX,corner.houyi.baofeng.net,AdBlock\n - DOMAIN-SUFFIX,coro.benbaisteel.com,AdBlock\n - DOMAIN-SUFFIX,corocksi.com,AdBlock\n - DOMAIN-SUFFIX,corp.meitu.com,AdBlock\n - DOMAIN-SUFFIX,corp.sohu.com,AdBlock\n - DOMAIN-SUFFIX,cosoyoo.com,AdBlock\n - DOMAIN-SUFFIX,count.cpm.cm.kankan.com,AdBlock\n - DOMAIN-SUFFIX,count.knowsky.com,AdBlock\n - DOMAIN-SUFFIX,count.mail.163.com,AdBlock\n - DOMAIN-SUFFIX,count.pcpop.com,AdBlock\n - DOMAIN-SUFFIX,count.video.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,count.wk2.com,AdBlock\n - DOMAIN-SUFFIX,count5.pconline.com.cn,AdBlock\n - DOMAIN-SUFFIX,count6.pconline.com.cn,AdBlock\n - DOMAIN-SUFFIX,counter.csdn.net,AdBlock\n - DOMAIN-SUFFIX,counter.kingsoft.com,AdBlock\n - DOMAIN-SUFFIX,counter.m1905.com,AdBlock\n - DOMAIN-SUFFIX,counter.marketgid.com,AdBlock\n - DOMAIN-SUFFIX,counter.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,counter.yadro.ru,AdBlock\n - DOMAIN-SUFFIX,counter.yesky.com,AdBlock\n - DOMAIN-SUFFIX,countpvn.light.fang.com,AdBlock\n - DOMAIN-SUFFIX,countubn.light.soufun.com,AdBlock\n - DOMAIN-SUFFIX,couqm.com.cn,AdBlock\n - DOMAIN-SUFFIX,cp.5jjx.net,AdBlock\n - DOMAIN-SUFFIX,cp.ggyapp.com,AdBlock\n - DOMAIN-SUFFIX,cp.greenxf.cn,AdBlock\n - DOMAIN-SUFFIX,cp.gs307.com,AdBlock\n - DOMAIN-SUFFIX,cp.jfcdns.com,AdBlock\n - DOMAIN-SUFFIX,cp.jz5u.net,AdBlock\n - DOMAIN-SUFFIX,cpc.sogou.com,AdBlock\n - DOMAIN-SUFFIX,cpc.sohu.com,AdBlock\n - DOMAIN-SUFFIX,cpcv.cc,AdBlock\n - DOMAIN-SUFFIX,cpm.amateurcommunity.com,AdBlock\n - DOMAIN-SUFFIX,cpm.amateurcommunity.de,AdBlock\n - DOMAIN-SUFFIX,cpm.cm.sandai.net,AdBlock\n - DOMAIN-SUFFIX,cpmchina.co,AdBlock\n - DOMAIN-SUFFIX,cpms.cc,AdBlock\n - DOMAIN-SUFFIX,cpro.9xu.com,AdBlock\n - DOMAIN-SUFFIX,cpro.baidu.cn,AdBlock\n - DOMAIN-SUFFIX,cpro.baidu.com,AdBlock\n - DOMAIN-SUFFIX,cpro.fangtoo.com,AdBlock\n - DOMAIN-SUFFIX,cpro.zhidao.baidu.com,AdBlock\n - DOMAIN-SUFFIX,cpro.zol.com.cn,AdBlock\n - DOMAIN-SUFFIX,cpro1.edushi.com,AdBlock\n - DOMAIN-SUFFIX,cpro2.baidu.com,AdBlock\n - DOMAIN-SUFFIX,cps.360buy.com,AdBlock\n - DOMAIN-SUFFIX,cpu-admin.baidu.com,AdBlock\n - DOMAIN-SUFFIX,cpv.channelray,AdBlock\n - DOMAIN-SUFFIX,cpv.czpush.com,AdBlock\n - DOMAIN-SUFFIX,cpv.ty229.com,AdBlock\n - DOMAIN-SUFFIX,cpv6.com,AdBlock\n - DOMAIN-SUFFIX,cpva.cc,AdBlock\n - DOMAIN-SUFFIX,cpv-adv.ggytc.com,AdBlock\n - DOMAIN-SUFFIX,cpx24.com,AdBlock\n - DOMAIN-SUFFIX,cqfangduan.com,AdBlock\n - DOMAIN-SUFFIX,cqftonline.com,AdBlock\n - DOMAIN-SUFFIX,cqhnm.com,AdBlock\n - DOMAIN-SUFFIX,cqhot.club,AdBlock\n - DOMAIN-SUFFIX,cqsta.com,AdBlock\n - DOMAIN-SUFFIX,cqyhd.com,AdBlock\n - DOMAIN-SUFFIX,cr.m.liebao.cn,AdBlock\n - DOMAIN-SUFFIX,crashapi.growingio.com,AdBlock\n - DOMAIN-SUFFIX,crashes.mo.wps.cn,AdBlock\n - DOMAIN-SUFFIX,crasheye.cn,AdBlock\n - DOMAIN-SUFFIX,crashlytics.163.com,AdBlock\n - DOMAIN-SUFFIX,crashlytics.com,AdBlock\n - DOMAIN-SUFFIX,crdrjs.info,AdBlock\n - DOMAIN-SUFFIX,cre.dp.sina.cn,AdBlock\n - DOMAIN-SUFFIX,cre.mix.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,cre99.com,AdBlock\n - DOMAIN-SUFFIX,creatim.qtmojo.cn,AdBlock\n - DOMAIN-SUFFIX,creative.1111cpc.com,AdBlock\n - DOMAIN-SUFFIX,creative.jdkic.com,AdBlock\n - DOMAIN-SUFFIX,creative.ltheanine.cn,AdBlock\n - DOMAIN-SUFFIX,creatives.cliphunter.com,AdBlock\n - DOMAIN-SUFFIX,creatives.ftchinese.com,AdBlock\n - DOMAIN-SUFFIX,creatives.inmotionhosting.com,AdBlock\n - DOMAIN-SUFFIX,creatives.livejasmin.com,AdBlock\n - DOMAIN-SUFFIX,creatives.pichunter.com,AdBlock\n - DOMAIN-SUFFIX,creatives.summitconnect.co.uk,AdBlock\n - DOMAIN-SUFFIX,creatives1.ftimg.net,AdBlock\n - DOMAIN-SUFFIX,cre-dp.sina.cn,AdBlock\n - DOMAIN-SUFFIX,criteo.com,AdBlock\n - DOMAIN-SUFFIX,criteo.net,AdBlock\n - DOMAIN-SUFFIX,crl.microsoft.com,AdBlock\n - DOMAIN-SUFFIX,crm-eve.b2b.alibaba-inc.com,AdBlock\n - DOMAIN-SUFFIX,cr-nielsen.com,AdBlock\n - DOMAIN-SUFFIX,crosschannel.com,AdBlock\n - DOMAIN-SUFFIX,crossoverchina.com,AdBlock\n - DOMAIN-SUFFIX,cr-p16.ladsp.com,AdBlock\n - DOMAIN-SUFFIX,crs.baidu.com,AdBlock\n - DOMAIN-SUFFIX,crwdcntrl.net,AdBlock\n - DOMAIN-SUFFIX,cs.dqwjzm.com,AdBlock\n - DOMAIN-SUFFIX,cs.twcczhu.com,AdBlock\n - DOMAIN-SUFFIX,csad.cc,AdBlock\n - DOMAIN-SUFFIX,csbew.com,AdBlock\n - DOMAIN-SUFFIX,csi.gstatic.com,AdBlock\n - DOMAIN-SUFFIX,csqiulong.com,AdBlock\n - DOMAIN-SUFFIX,cstoa.com,AdBlock\n - DOMAIN-SUFFIX,csxjys.com,AdBlock\n - DOMAIN-SUFFIX,cszlks.com,AdBlock\n - DOMAIN-SUFFIX,ct.210189.com,AdBlock\n - DOMAIN-SUFFIX,ct.niu.xunlei.com,AdBlock\n - DOMAIN-SUFFIX,cti.w55c.net,AdBlock\n - DOMAIN-SUFFIX,ctrmi.com,AdBlock\n - DOMAIN-SUFFIX,ctsywy.com,AdBlock\n - DOMAIN-SUFFIX,cudaojia.com,AdBlock\n - DOMAIN-SUFFIX,cupid.jebe.renren.com,AdBlock\n - DOMAIN-SUFFIX,current.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,customad.cnn.com,AdBlock\n - DOMAIN-SUFFIX,customer-security.online,AdBlock\n - DOMAIN-SUFFIX,cut.qumi.com,AdBlock\n - DOMAIN-SUFFIX,cvda.17173.com,AdBlock\n - DOMAIN-SUFFIX,cvt.mydas.mobi,AdBlock\n - DOMAIN-SUFFIX,cwpush.com,AdBlock\n - DOMAIN-SUFFIX,cws-cctv.conviva.com,AdBlock\n - DOMAIN-SUFFIX,cy123.cc,AdBlock\n - DOMAIN-SUFFIX,cyacc.com,AdBlock\n - DOMAIN-SUFFIX,cyad.cc,AdBlock\n - DOMAIN-SUFFIX,cyad1.cyworld.com,AdBlock\n - DOMAIN-SUFFIX,cyad1.nate.com,AdBlock\n - DOMAIN-SUFFIX,cyad123.com,AdBlock\n - DOMAIN-SUFFIX,cycy.kxrxh.com,AdBlock\n - DOMAIN-SUFFIX,cylinderlongcheng.com,AdBlock\n - DOMAIN-SUFFIX,cyylove.com,AdBlock\n - DOMAIN-SUFFIX,cz.ifeng0.com,AdBlock\n - DOMAIN-SUFFIX,cz01016102.cg2017.com,AdBlock\n - DOMAIN-SUFFIX,cz01016102.ms758.com,AdBlock\n - DOMAIN-SUFFIX,czdqhyo1.net,AdBlock\n - DOMAIN-SUFFIX,czf.cchfjz.com,AdBlock\n - DOMAIN-SUFFIX,czjiuding.cn,AdBlock\n - DOMAIN-SUFFIX,czpush.com,AdBlock\n - DOMAIN-SUFFIX,czpwm.com,AdBlock\n - DOMAIN-SUFFIX,czxiangyue.com,AdBlock\n - DOMAIN-SUFFIX,d.107788.com,AdBlock\n - DOMAIN-SUFFIX,d.1391.com,AdBlock\n - DOMAIN-SUFFIX,d.39.net,AdBlock\n - DOMAIN-SUFFIX,d.admx.baixing.com,AdBlock\n - DOMAIN-SUFFIX,d.agkn.com,AdBlock\n - DOMAIN-SUFFIX,d.annarbor.com,AdBlock\n - DOMAIN-SUFFIX,d.beigedi.com,AdBlock\n - DOMAIN-SUFFIX,d.businessinsider.com,AdBlock\n - DOMAIN-SUFFIX,d.clkservice.youdao.com,AdBlock\n - DOMAIN-SUFFIX,d.danangmo.cn,AdBlock\n - DOMAIN-SUFFIX,d.elong.cn,AdBlock\n - DOMAIN-SUFFIX,d.gossipcenter.com,AdBlock\n - DOMAIN-SUFFIX,d.kugou.com,AdBlock\n - DOMAIN-SUFFIX,d.ligatus.com,AdBlock\n - DOMAIN-SUFFIX,d.mingyihui.net,AdBlock\n - DOMAIN-SUFFIX,d.rexuebi.com,AdBlock\n - DOMAIN-SUFFIX,d.ruiwen.com,AdBlock\n - DOMAIN-SUFFIX,d.thelocal.com,AdBlock\n - DOMAIN-SUFFIX,d.tjgxzs.com,AdBlock\n - DOMAIN-SUFFIX,d.tonghua5.com,AdBlock\n - DOMAIN-SUFFIX,d.turn.com,AdBlock\n - DOMAIN-SUFFIX,d.union.ijinshan.com,AdBlock\n - DOMAIN-SUFFIX,d.xinshipu.com,AdBlock\n - DOMAIN-SUFFIX,d.yjbys.com,AdBlock\n - DOMAIN-SUFFIX,d.yoyi.com.cn,AdBlock\n - DOMAIN-SUFFIX,d.yoyi.tv,AdBlock\n - DOMAIN-SUFFIX,d0.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,d0.sinaimg.cn,AdBlock\n - DOMAIN-SUFFIX,d0.xcar.com.cn,AdBlock\n - DOMAIN-SUFFIX,d00.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,d1.showself.com,AdBlock\n - DOMAIN-SUFFIX,d1.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,d1.sinaimg.cn,AdBlock\n - DOMAIN-SUFFIX,d1ad.com,AdBlock\n - DOMAIN-SUFFIX,d1grtyyel8f1mh.cloudfront.net,AdBlock\n - DOMAIN-SUFFIX,d1zgderxoe1a.cloudfront.net,AdBlock\n - DOMAIN-SUFFIX,d2.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,d2.sinaimg.cn,AdBlock\n - DOMAIN-SUFFIX,d2.yiche.com,AdBlock\n - DOMAIN-SUFFIX,d29qt51jeyi6xb.cloudfront.net,AdBlock\n - DOMAIN-SUFFIX,d2qkpebv23oowx.cloudfront.net,AdBlock\n - DOMAIN-SUFFIX,d3.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,d3.sinaimg.cn,AdBlock\n - DOMAIN-SUFFIX,d31qbv1cthcecs.cloudfront.net,AdBlock\n - DOMAIN-SUFFIX,d36eyd5j1kt1m6.cloudfront.net,AdBlock\n - DOMAIN-SUFFIX,d3f.houyi.baofeng.net,AdBlock\n - DOMAIN-SUFFIX,d3g.qq.com,AdBlock\n - DOMAIN-SUFFIX,d3v1lb83psg9di.cloudfront.net,AdBlock\n - DOMAIN-SUFFIX,d4.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,d5.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,d520m.gzcl999.cn,AdBlock\n - DOMAIN-SUFFIX,d5nxst8fruw4z.cloudfront.net,AdBlock\n - DOMAIN-SUFFIX,d5p.de17a.com,AdBlock\n - DOMAIN-SUFFIX,d6.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,d6.sinaimg.cn,AdBlock\n - DOMAIN-SUFFIX,d7.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,d7.sinaimg.cn,AdBlock\n - DOMAIN-SUFFIX,d77777777.com,AdBlock\n - DOMAIN-SUFFIX,d8.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,d8.sinaimg.cn,AdBlock\n - DOMAIN-SUFFIX,d8.zedo.com,AdBlock\n - DOMAIN-SUFFIX,d8360.com,AdBlock\n - DOMAIN-SUFFIX,d8885.com,AdBlock\n - DOMAIN-SUFFIX,d9.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,daa.shuzilm.cn,AdBlock\n - DOMAIN-SUFFIX,dacash.streamplay.to,AdBlock\n - DOMAIN-SUFFIX,dadjia.com,AdBlock\n - DOMAIN-SUFFIX,dads.new.digg.com,AdBlock\n - DOMAIN-SUFFIX,dafahao.com,AdBlock\n - DOMAIN-SUFFIX,dafahao.org,AdBlock\n - DOMAIN-SUFFIX,dafapromo.com,AdBlock\n - DOMAIN-SUFFIX,dahanedu.com,AdBlock\n - DOMAIN-SUFFIX,dai.shuzilm.cn,AdBlock\n - DOMAIN-SUFFIX,dailydeals.amarillo.com,AdBlock\n - DOMAIN-SUFFIX,dailydeals.augustachronicle.com,AdBlock\n - DOMAIN-SUFFIX,dailydeals.brainerddispatch.com,AdBlock\n - DOMAIN-SUFFIX,dailydeals.lubbockonline.com,AdBlock\n - DOMAIN-SUFFIX,dailydeals.onlineathens.com,AdBlock\n - DOMAIN-SUFFIX,dailydeals.savannahnow.com,AdBlock\n - DOMAIN-SUFFIX,dailylog.storm.baofeng.com,AdBlock\n - DOMAIN-SUFFIX,dailyvideo.securejoin.com,AdBlock\n - DOMAIN-SUFFIX,daima.23yy.com,AdBlock\n - DOMAIN-SUFFIX,daima.chazidian.com,AdBlock\n - DOMAIN-SUFFIX,daima.diaoben.net,AdBlock\n - DOMAIN-SUFFIX,daima.dsxdn.com,AdBlock\n - DOMAIN-SUFFIX,daima.huoche.net,AdBlock\n - DOMAIN-SUFFIX,daima.ijq.tv,AdBlock\n - DOMAIN-SUFFIX,daima.mubite.cn,AdBlock\n - DOMAIN-SUFFIX,daima.youbian.com,AdBlock\n - DOMAIN-SUFFIX,daima123.cc,AdBlock\n - DOMAIN-SUFFIX,dairuqi.com,AdBlock\n - DOMAIN-SUFFIX,daitdai.com,AdBlock\n - DOMAIN-SUFFIX,dajean.com,AdBlock\n - DOMAIN-SUFFIX,dajiyuan.com,AdBlock\n - DOMAIN-SUFFIX,dajiyuan.org,AdBlock\n - DOMAIN-SUFFIX,dalianhengtai.com,AdBlock\n - DOMAIN-SUFFIX,dandan11.top,AdBlock\n - DOMAIN-SUFFIX,dandan13.top,AdBlock\n - DOMAIN-SUFFIX,dandan15.top,AdBlock\n - DOMAIN-SUFFIX,danpinwu.com,AdBlock\n - DOMAIN-SUFFIX,dante2007.com,AdBlock\n - DOMAIN-SUFFIX,daohang.114so.cn,AdBlock\n - DOMAIN-SUFFIX,daoyoudao.com,AdBlock\n - DOMAIN-SUFFIX,dap.pagechoice.net,AdBlock\n - DOMAIN-SUFFIX,dart.clearchannel.com,AdBlock\n - DOMAIN-SUFFIX,dashet.com,AdBlock\n - DOMAIN-SUFFIX,data.3975.com,AdBlock\n - DOMAIN-SUFFIX,data.ad-score.com,AdBlock\n - DOMAIN-SUFFIX,data.apn.co.nz,AdBlock\n - DOMAIN-SUFFIX,data.danmu.baofeng.com,AdBlock\n - DOMAIN-SUFFIX,data.doodlemobile.com,AdBlock\n - DOMAIN-SUFFIX,data.gosquared.com,AdBlock\n - DOMAIN-SUFFIX,data.mistat.xiaomi.com,AdBlock\n - DOMAIN-SUFFIX,data.neuroxmedia.com,AdBlock\n - DOMAIN-SUFFIX,data2.doodlemobile.com,AdBlock\n - DOMAIN-SUFFIX,data2.gosquared.com,AdBlock\n - DOMAIN-SUFFIX,databank.air.yoyi.com.cn,AdBlock\n - DOMAIN-SUFFIX,databank.yoyi.com.cn,AdBlock\n - DOMAIN-SUFFIX,datacapture.serving-sys.com,AdBlock\n - DOMAIN-SUFFIX,datafastguru.info,AdBlock\n - DOMAIN-SUFFIX,data-news.cdn.cootekservice.com,AdBlock\n - DOMAIN-SUFFIX,data-pic.cdn.cootekservice.com,AdBlock\n - DOMAIN-SUFFIX,datax.baidu.com,AdBlock\n - DOMAIN-SUFFIX,datouniao.com,AdBlock\n - DOMAIN-SUFFIX,dawwx.com,AdBlock\n - DOMAIN-SUFFIX,day66.com,AdBlock\n - DOMAIN-SUFFIX,dazhantai.com,AdBlock\n - DOMAIN-SUFFIX,dazhonghua.cn,AdBlock\n - DOMAIN-SUFFIX,db1.fuz.cc,AdBlock\n - DOMAIN-SUFFIX,db2.fuz.cc,AdBlock\n - DOMAIN-SUFFIX,dbam.dashbida.com,AdBlock\n - DOMAIN-SUFFIX,dbncp.com,AdBlock\n - DOMAIN-SUFFIX,dbregistration.cuteftp.com,AdBlock\n - DOMAIN-SUFFIX,dbwmjj.com,AdBlock\n - DOMAIN-SUFFIX,dc.cp21.ott.cibntv.net,AdBlock\n - DOMAIN-SUFFIX,dc.csdn.net,AdBlock\n - DOMAIN-SUFFIX,dc.liuliang100.com,AdBlock\n - DOMAIN-SUFFIX,dc.meitustat.com,AdBlock\n - DOMAIN-SUFFIX,dc.vmoters.com,AdBlock\n - DOMAIN-SUFFIX,dc.xhct66.com,AdBlock\n - DOMAIN-SUFFIX,dc2.csdn.net,AdBlock\n - DOMAIN-SUFFIX,d-cache.microad-cn.com,AdBlock\n - DOMAIN-SUFFIX,dcad.watersoul.com,AdBlock\n - DOMAIN-SUFFIX,dcads.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,dcapps.disney.go.com,AdBlock\n - DOMAIN-SUFFIX,dcjs.cig.com.cn,AdBlock\n - DOMAIN-SUFFIX,dcw.hdswgc.com,AdBlock\n - DOMAIN-SUFFIX,dd.70yst.com,AdBlock\n - DOMAIN-SUFFIX,dd.dante2007.com,AdBlock\n - DOMAIN-SUFFIX,dd.iask.cn,AdBlock\n - DOMAIN-SUFFIX,dd.iaskgo.com,AdBlock\n - DOMAIN-SUFFIX,dd.mangofortune.net,AdBlock\n - DOMAIN-SUFFIX,dd.wx16999.com,AdBlock\n - DOMAIN-SUFFIX,ddanq.com,AdBlock\n - DOMAIN-SUFFIX,ddapp.cn,AdBlock\n - DOMAIN-SUFFIX,ddd.haodizhi666.com,AdBlock\n - DOMAIN-SUFFIX,ddd.yuyouge.com,AdBlock\n - DOMAIN-SUFFIX,ddg1277.com,AdBlock\n - DOMAIN-SUFFIX,ddhtek.com,AdBlock\n - DOMAIN-SUFFIX,ddkkrrla.m.qxs.la,AdBlock\n - DOMAIN-SUFFIX,ddomm.com,AdBlock\n - DOMAIN-SUFFIX,ddpxhq.cn,AdBlock\n - DOMAIN-SUFFIX,ddrrccck.m.qxs.la,AdBlock\n - DOMAIN-SUFFIX,de.as.cp61.ott.cibntv.net,AdBlock\n - DOMAIN-SUFFIX,de.dzribao.com,AdBlock\n - DOMAIN-SUFFIX,de.ioam.de,AdBlock\n - DOMAIN-SUFFIX,de.pandora.xiaomi.com,AdBlock\n - DOMAIN-SUFFIX,deals.ledgertranscript.com,AdBlock\n - DOMAIN-SUFFIX,debugreport.mobiledissector.com,AdBlock\n - DOMAIN-SUFFIX,dejing.laobanfa.com,AdBlock\n - DOMAIN-SUFFIX,deletemer.online,AdBlock\n - DOMAIN-SUFFIX,deliver.kuwo.cn,AdBlock\n - DOMAIN-SUFFIX,delivery.maihehd.com,AdBlock\n - DOMAIN-SUFFIX,delivery.playallvideos.com,AdBlock\n - DOMAIN-SUFFIX,delivery.porn.com,AdBlock\n - DOMAIN-SUFFIX,delivery.wasu.cn,AdBlock\n - DOMAIN-SUFFIX,delivery-pc.wasu.cn,AdBlock\n - DOMAIN-SUFFIX,demo.jointreport-switch.com,AdBlock\n - DOMAIN-SUFFIX,desk.cmix.org,AdBlock\n - DOMAIN-SUFFIX,detuns.com,AdBlock\n - DOMAIN-SUFFIX,dev.tg.youxi.com,AdBlock\n - DOMAIN-SUFFIX,devs.data.mob.com,AdBlock\n - DOMAIN-SUFFIX,dezfu.com,AdBlock\n - DOMAIN-SUFFIX,df3n43m.com,AdBlock\n - DOMAIN-SUFFIX,df77.com,AdBlock\n - DOMAIN-SUFFIX,dfad.dfdaily.com,AdBlock\n - DOMAIN-SUFFIX,dfc1.benbaisteel.com,AdBlock\n - DOMAIN-SUFFIX,dfp.suning.com,AdBlock\n - DOMAIN-SUFFIX,dfx.shhuixiangwuliu.com,AdBlock\n - DOMAIN-SUFFIX,dfx.vnnv777.cn,AdBlock\n - DOMAIN-SUFFIX,dgfggy.com,AdBlock\n - DOMAIN-SUFFIX,dgpzx.com,AdBlock\n - DOMAIN-SUFFIX,dh.holaworld.cn,AdBlock\n - DOMAIN-SUFFIX,dhxyzx.cn,AdBlock\n - DOMAIN-SUFFIX,diag-vd.gridsumdissector.com,AdBlock\n - DOMAIN-SUFFIX,diag-wd.gridsumdissector.com,AdBlock\n - DOMAIN-SUFFIX,dialer.cdn.cootekservice.com,AdBlock\n - DOMAIN-SUFFIX,dianjoy.com,AdBlock\n - DOMAIN-SUFFIX,dianru.com,AdBlock\n - DOMAIN-SUFFIX,diaojiaoji168.com,AdBlock\n - DOMAIN-SUFFIX,diaopic.14bobo.com,AdBlock\n - DOMAIN-SUFFIX,diediao.com,AdBlock\n - DOMAIN-SUFFIX,difnxm.cn,AdBlock\n - DOMAIN-SUFFIX,digdug.divxnetworks.com,AdBlock\n - DOMAIN-SUFFIX,dimg1.sz.net.cn,AdBlock\n - DOMAIN-SUFFIX,dingon.com.cn,AdBlock\n - DOMAIN-SUFFIX,dip.pyangzi.com,AdBlock\n - DOMAIN-SUFFIX,dip.szhyzkj.com,AdBlock\n - DOMAIN-SUFFIX,dip.wl963.com,AdBlock\n - DOMAIN-SUFFIX,dip.zgydjr.com,AdBlock\n - DOMAIN-SUFFIX,dipan.com,AdBlock\n - DOMAIN-SUFFIX,directrev.com,AdBlock\n - DOMAIN-SUFFIX,dis.crieto.com,AdBlock\n - DOMAIN-SUFFIX,dis.criteo.com,AdBlock\n - DOMAIN-SUFFIX,dis.us.criteo.com,AdBlock\n - DOMAIN-SUFFIX,discuz.gtimg.cn,AdBlock\n - DOMAIN-SUFFIX,dispenser-rtb.sape.ru,AdBlock\n - DOMAIN-SUFFIX,display.360totalsecurity.com,AdBlock\n - DOMAIN-SUFFIX,display.ad.daum.net,AdBlock\n - DOMAIN-SUFFIX,display.adhudong.com,AdBlock\n - DOMAIN-SUFFIX,display.digitalriver.com,AdBlock\n - DOMAIN-SUFFIX,display.superbay.net,AdBlock\n - DOMAIN-SUFFIX,disqusads.com,AdBlock\n - DOMAIN-SUFFIX,distf.kankan.com,AdBlock\n - DOMAIN-SUFFIX,diyxjd.com,AdBlock\n - DOMAIN-SUFFIX,djs.baomihua.com,AdBlock\n - DOMAIN-SUFFIX,dkdlsj.com,AdBlock\n - DOMAIN-SUFFIX,dkeyn.com,AdBlock\n - DOMAIN-SUFFIX,dl.2345.com,AdBlock\n - DOMAIN-SUFFIX,dl.360safe.com,AdBlock\n - DOMAIN-SUFFIX,dl.9xu.com,AdBlock\n - DOMAIN-SUFFIX,dl.client.baidu.com,AdBlock\n - DOMAIN-SUFFIX,dl.cm.ksmobile.com,AdBlock\n - DOMAIN-SUFFIX,dl.eduancm.com,AdBlock\n - DOMAIN-SUFFIX,dl.img80.net,AdBlock\n - DOMAIN-SUFFIX,dl.jianshunrui.com,AdBlock\n - DOMAIN-SUFFIX,dl.kinbest.cn,AdBlock\n - DOMAIN-SUFFIX,dl.kjava.sina.cn,AdBlock\n - DOMAIN-SUFFIX,dl.mbsea.com,AdBlock\n - DOMAIN-SUFFIX,dl.nx5.com,AdBlock\n - DOMAIN-SUFFIX,dl.ops.baidu.com,AdBlock\n - DOMAIN-SUFFIX,dl.sybspools.com,AdBlock\n - DOMAIN-SUFFIX,dl.union.ijinshan.com,AdBlock\n - DOMAIN-SUFFIX,dl.uu.cc,AdBlock\n - DOMAIN-SUFFIX,dl.wan.sogoucdn.com,AdBlock\n - DOMAIN-SUFFIX,dl.xzqxzs.com,AdBlock\n - DOMAIN-SUFFIX,dl.youjia2016.com,AdBlock\n - DOMAIN-SUFFIX,dl1sw.baidu.com,AdBlock\n - DOMAIN-SUFFIX,dl2.bav.baidu.com,AdBlock\n - DOMAIN-SUFFIX,dleke.com,AdBlock\n - DOMAIN-SUFFIX,dlimg.lovfp.com,AdBlock\n - DOMAIN-SUFFIX,dload.qd.qingting.fm,AdBlock\n - DOMAIN-SUFFIX,dlpifu.com,AdBlock\n - DOMAIN-SUFFIX,dlrijiaele.com,AdBlock\n - DOMAIN-SUFFIX,dlsw.baidu.com,AdBlock\n - DOMAIN-SUFFIX,dlsw.br.baidu.com,AdBlock\n - DOMAIN-SUFFIX,dl-vip.bav.baidu.com,AdBlock\n - DOMAIN-SUFFIX,dl-vip.pcfaster.baidu.co.th,AdBlock\n - DOMAIN-SUFFIX,dlzjdesign.com,AdBlock\n - DOMAIN-SUFFIX,dm.388g.cc,AdBlock\n - DOMAIN-SUFFIX,dm.51okc.com,AdBlock\n - DOMAIN-SUFFIX,dm.92to.com,AdBlock\n - DOMAIN-SUFFIX,dm.aizhan.com,AdBlock\n - DOMAIN-SUFFIX,dm.bytedance.com,AdBlock\n - DOMAIN-SUFFIX,dm.chalook.net,AdBlock\n - DOMAIN-SUFFIX,dm.fsyzcs.com,AdBlock\n - DOMAIN-SUFFIX,dm.gbeik.com,AdBlock\n - DOMAIN-SUFFIX,dm.jb51.net,AdBlock\n - DOMAIN-SUFFIX,dm.jinshasi.cn,AdBlock\n - DOMAIN-SUFFIX,dm.jsyst.cn,AdBlock\n - DOMAIN-SUFFIX,dm.jy135.com,AdBlock\n - DOMAIN-SUFFIX,dm.ppzuowen.com,AdBlock\n - DOMAIN-SUFFIX,dm.pstatp.com,AdBlock\n - DOMAIN-SUFFIX,dm.pw0.cn,AdBlock\n - DOMAIN-SUFFIX,dm.riji.cn,AdBlock\n - DOMAIN-SUFFIX,dm.sanwen.net,AdBlock\n - DOMAIN-SUFFIX,dm.sanwen8.com,AdBlock\n - DOMAIN-SUFFIX,dm.sb580.com,AdBlock\n - DOMAIN-SUFFIX,dm.toutiao.com,AdBlock\n - DOMAIN-SUFFIX,dm.ws8.org,AdBlock\n - DOMAIN-SUFFIX,dm.yjbys.com,AdBlock\n - DOMAIN-SUFFIX,dm1.tom61.com,AdBlock\n - DOMAIN-SUFFIX,dm50.jkyd.net,AdBlock\n - DOMAIN-SUFFIX,dm50.yxlady.com,AdBlock\n - DOMAIN-SUFFIX,dmacore.kejet.com,AdBlock\n - DOMAIN-SUFFIX,dmacore.kejet.net,AdBlock\n - DOMAIN-SUFFIX,dmg.digitaltarget.ru,AdBlock\n - DOMAIN-SUFFIX,dmp.kejet.net,AdBlock\n - DOMAIN-SUFFIX,dmp.sina.cn,AdBlock\n - DOMAIN-SUFFIX,dmpclick.deliver.ifeng.com,AdBlock\n - DOMAIN-SUFFIX,dmrtb.com,AdBlock\n - DOMAIN-SUFFIX,dmt.qcrx.cn,AdBlock\n - DOMAIN-SUFFIX,dmtrck.com,AdBlock\n - DOMAIN-SUFFIX,dn3.ixinwei.com,AdBlock\n - DOMAIN-SUFFIX,dn7788.com,AdBlock\n - DOMAIN-SUFFIX,dn-growing.qbox.me,AdBlock\n - DOMAIN-SUFFIX,dnvus.com,AdBlock\n - DOMAIN-SUFFIX,do.lymstsc.com,AdBlock\n - DOMAIN-SUFFIX,do69ifsly4.me,AdBlock\n - DOMAIN-SUFFIX,doc.go.sohu.com,AdBlock\n - DOMAIN-SUFFIX,dol.deliver.ifeng.com,AdBlock\n - DOMAIN-SUFFIX,dolphin.deliver.ifeng.com,AdBlock\n - DOMAIN-SUFFIX,dolphin.ftimg.net,AdBlock\n - DOMAIN-SUFFIX,dolphin4.ftimg.net,AdBlock\n - DOMAIN-SUFFIX,doubleclick.net,AdBlock\n - DOMAIN-SUFFIX,domed.shenbimall.com,AdBlock\n - DOMAIN-SUFFIX,do-not-tracker.org,AdBlock\n - DOMAIN-SUFFIX,dontblockme.modaco.com,AdBlock\n - DOMAIN-SUFFIX,dopa.com,AdBlock\n - DOMAIN-SUFFIX,dot.eporner.com,AdBlock\n - DOMAIN-SUFFIX,dot2.eporner.com,AdBlock\n - DOMAIN-SUFFIX,dotmore.com.tw,AdBlock\n - DOMAIN-SUFFIX,dou777.com,AdBlock\n - DOMAIN-SUFFIX,doubleplay-conf-yql.media.yahoo.com,AdBlock\n - DOMAIN-SUFFIX,doubleverify.com,AdBlock\n - DOMAIN-SUFFIX,doudao.cn,AdBlock\n - DOMAIN-SUFFIX,doudouguo.com,AdBlock\n - DOMAIN-SUFFIX,dougou88.com,AdBlock\n - DOMAIN-SUFFIX,doumob.com,AdBlock\n - DOMAIN-SUFFIX,down.360safe.com,AdBlock\n - DOMAIN-SUFFIX,down.91wangmeng.com,AdBlock\n - DOMAIN-SUFFIX,down.bugeyu.com,AdBlock\n - DOMAIN-SUFFIX,down.dashendown.com,AdBlock\n - DOMAIN-SUFFIX,down.diannaodian.com,AdBlock\n - DOMAIN-SUFFIX,down.laomaotao.net,AdBlock\n - DOMAIN-SUFFIX,down.winads.cn,AdBlock\n - DOMAIN-SUFFIX,down.winbaicai.com,AdBlock\n - DOMAIN-SUFFIX,down.xiazaidc.com,AdBlock\n - DOMAIN-SUFFIX,down.xiazaiyuan.net,AdBlock\n - DOMAIN-SUFFIX,downlaod.xiaocen.com,AdBlock\n - DOMAIN-SUFFIX,download.123cw.cn,AdBlock\n - DOMAIN-SUFFIX,download.2345.com,AdBlock\n - DOMAIN-SUFFIX,download.350.com,AdBlock\n - DOMAIN-SUFFIX,download.bav.baidu.com,AdBlock\n - DOMAIN-SUFFIX,download.coolguang.com,AdBlock\n - DOMAIN-SUFFIX,download.fuyuncc.com,AdBlock\n - DOMAIN-SUFFIX,download.mediaget.com,AdBlock\n - DOMAIN-SUFFIX,download.qianka.com,AdBlock\n - DOMAIN-SUFFIX,download.sd.baidu.com,AdBlock\n - DOMAIN-SUFFIX,download.sj.qq.com,AdBlock\n - DOMAIN-SUFFIX,download.zhushou.sogou.com,AdBlock\n - DOMAIN-SUFFIX,download3.123cw.cn,AdBlock\n - DOMAIN-SUFFIX,downloada.dewmobile.net,AdBlock\n - DOMAIN-SUFFIX,downloadb.dewmobile.net,AdBlock\n - DOMAIN-SUFFIX,downmobile.kugou.com,AdBlock\n - DOMAIN-SUFFIX,dp.559.cc,AdBlock\n - DOMAIN-SUFFIX,dpm.demdex.net,AdBlock\n - DOMAIN-SUFFIX,dps.499.cn,AdBlock\n - DOMAIN-SUFFIX,dps.shouji56.com,AdBlock\n - DOMAIN-SUFFIX,dps.wtdtjs.com,AdBlock\n - DOMAIN-SUFFIX,dpvc.39.net,AdBlock\n - DOMAIN-SUFFIX,dpvc1.qqyy.com,AdBlock\n - DOMAIN-SUFFIX,dpvc2.qqyy.com,AdBlock\n - DOMAIN-SUFFIX,dpvchos.qqyy.com,AdBlock\n - DOMAIN-SUFFIX,dpvcimg.qqyy.com,AdBlock\n - DOMAIN-SUFFIX,dqq.lnfund.org.cn,AdBlock\n - DOMAIN-SUFFIX,dqsft.com,AdBlock\n - DOMAIN-SUFFIX,dr.holaworld.cn,AdBlock\n - DOMAIN-SUFFIX,dragoncent.com,AdBlock\n - DOMAIN-SUFFIX,drd.hauchi.com.tw,AdBlock\n - DOMAIN-SUFFIX,drdj.m.gxwztv.com,AdBlock\n - DOMAIN-SUFFIX,drdwy.com,AdBlock\n - DOMAIN-SUFFIX,dreamfull.cn,AdBlock\n - DOMAIN-SUFFIX,dressimage.img-cn-beijing.aliyuncs.com,AdBlock\n - DOMAIN-SUFFIX,drlsf.com,AdBlock\n - DOMAIN-SUFFIX,drm.cmgame.com,AdBlock\n - DOMAIN-SUFFIX,drmcmm.baidu.com,AdBlock\n - DOMAIN-SUFFIX,drsw.m.yuyouge.com,AdBlock\n - DOMAIN-SUFFIX,drvmy.ats68.cn,AdBlock\n - DOMAIN-SUFFIX,drxrc.com,AdBlock\n - DOMAIN-SUFFIX,ds.jlbksy.com,AdBlock\n - DOMAIN-SUFFIX,ds.serving-sys.com,AdBlock\n - DOMAIN-SUFFIX,dsadas.hydp188.com,AdBlock\n - DOMAIN-SUFFIX,dsaeerf.com,AdBlock\n - DOMAIN-SUFFIX,dshrx.com,AdBlock\n - DOMAIN-SUFFIX,dsjsee.dqgpb.com,AdBlock\n - DOMAIN-SUFFIX,ds-ll.serving-sys.com,AdBlock\n - DOMAIN-SUFFIX,dsp.adfarm1.adition.com,AdBlock\n - DOMAIN-SUFFIX,dsp.com,AdBlock\n - DOMAIN-SUFFIX,dsp.hypers.com.cn,AdBlock\n - DOMAIN-SUFFIX,dsp.pro.cn,AdBlock\n - DOMAIN-SUFFIX,dsp.send.microad-cn.com,AdBlock\n - DOMAIN-SUFFIX,dsp.simba.taobao.com,AdBlock\n - DOMAIN-SUFFIX,dsp.toutiao.com,AdBlock\n - DOMAIN-SUFFIX,dsp.youdao.com,AdBlock\n - DOMAIN-SUFFIX,ds-pc.admsger.com,AdBlock\n - DOMAIN-SUFFIX,dsp-click.youdao.com,AdBlock\n - DOMAIN-SUFFIX,dsp-impr.youdao.com,AdBlock\n - DOMAIN-SUFFIX,dsp-impr2.youdao.com,AdBlock\n - DOMAIN-SUFFIX,dspmy.ge95.com,AdBlock\n - DOMAIN-SUFFIX,dspserver.ad.cmvideo.cn,AdBlock\n - DOMAIN-SUFFIX,ds-pv.iqu-operation.com,AdBlock\n - DOMAIN-SUFFIX,dsxdn.com,AdBlock\n - DOMAIN-SUFFIX,dt.adsafeprotected.com,AdBlock\n - DOMAIN-SUFFIX,d-track.send.microad-cn.com,AdBlock\n - DOMAIN-SUFFIX,dtrk.slimcdn.com,AdBlock\n - DOMAIN-SUFFIX,dts.akamai.startappexchange.com,AdBlock\n - DOMAIN-SUFFIX,duanat.com,AdBlock\n - DOMAIN-SUFFIX,duapp.com,AdBlock\n - DOMAIN-SUFFIX,duapps.com,AdBlock\n - DOMAIN-SUFFIX,dugbvb.com,AdBlock\n - DOMAIN-SUFFIX,dugesheying.com,AdBlock\n - DOMAIN-SUFFIX,duiwai.baidu.com,AdBlock\n - DOMAIN-SUFFIX,dumedia.ru,AdBlock\n - DOMAIN-SUFFIX,duoyidd.com,AdBlock\n - DOMAIN-SUFFIX,dushimj.com,AdBlock\n - DOMAIN-SUFFIX,duusuu.com,AdBlock\n - DOMAIN-SUFFIX,duyihu.net,AdBlock\n - DOMAIN-SUFFIX,dv8c1t.cn,AdBlock\n - DOMAIN-SUFFIX,dvb.pandora.xiaomi.com,AdBlock\n - DOMAIN-SUFFIX,dvr8.com,AdBlock\n - DOMAIN-SUFFIX,dvs.china.com,AdBlock\n - DOMAIN-SUFFIX,dvsend.china.com,AdBlock\n - DOMAIN-SUFFIX,dvser.china.com,AdBlock\n - DOMAIN-SUFFIX,dvser02.china.com,AdBlock\n - DOMAIN-SUFFIX,dvx-android.0.0.0.0.cn,AdBlock\n - DOMAIN-SUFFIX,dw.koudaibl.com,AdBlock\n - DOMAIN-SUFFIX,dw.xcar.com.cn,AdBlock\n - DOMAIN-SUFFIX,dw998.com,AdBlock\n - DOMAIN-SUFFIX,dwa.okwan.cn,AdBlock\n - DOMAIN-SUFFIX,dx1200.com,AdBlock\n - DOMAIN-SUFFIX,dxp.baidu.com,AdBlock\n - DOMAIN-SUFFIX,dxpmedia.com,AdBlock\n - DOMAIN-SUFFIX,dxprla.m.qxs.la,AdBlock\n - DOMAIN-SUFFIX,dxssiyi.com,AdBlock\n - DOMAIN-SUFFIX,dyb.jdcbuy.com,AdBlock\n - DOMAIN-SUFFIX,dydab.com,AdBlock\n - DOMAIN-SUFFIX,dyn.tnaflix.com,AdBlock\n - DOMAIN-SUFFIX,dynamic.aol.com,AdBlock\n - DOMAIN-SUFFIX,dynamic.zol.com.cn,AdBlock\n - DOMAIN-SUFFIX,dz2017.zdzxyplyt.com,AdBlock\n - DOMAIN-SUFFIX,dzais.com,AdBlock\n - DOMAIN-SUFFIX,dzisou.com,AdBlock\n - DOMAIN-SUFFIX,dzjzg.com,AdBlock\n - DOMAIN-SUFFIX,dzl.baidu.com,AdBlock\n - DOMAIN-SUFFIX,dzz.wankeedu.com,AdBlock\n - DOMAIN-SUFFIX,e.0.0.0.0.cn,AdBlock\n - DOMAIN-SUFFIX,e.0.0.0.0.com.cn,AdBlock\n - DOMAIN-SUFFIX,e.027blzs.com,AdBlock\n - DOMAIN-SUFFIX,e.0531mnk.net,AdBlock\n - DOMAIN-SUFFIX,e.1919388.net,AdBlock\n - DOMAIN-SUFFIX,e.28487.net,AdBlock\n - DOMAIN-SUFFIX,e.51xmgys.com,AdBlock\n - DOMAIN-SUFFIX,e.91.com,AdBlock\n - DOMAIN-SUFFIX,e.aa985.cn,AdBlock\n - DOMAIN-SUFFIX,e.acaog.com,AdBlock\n - DOMAIN-SUFFIX,e.acaox.com,AdBlock\n - DOMAIN-SUFFIX,e.admin60.com,AdBlock\n - DOMAIN-SUFFIX,e.afvfe.cn,AdBlock\n - DOMAIN-SUFFIX,e.anmeilai.net,AdBlock\n - DOMAIN-SUFFIX,e.apxyz.com,AdBlock\n - DOMAIN-SUFFIX,e.baidu.com,AdBlock\n - DOMAIN-SUFFIX,e.bapkt.com,AdBlock\n - DOMAIN-SUFFIX,e.bbvjs.com,AdBlock\n - DOMAIN-SUFFIX,e.bentengcn.com,AdBlock\n - DOMAIN-SUFFIX,e.bokanedu.net,AdBlock\n - DOMAIN-SUFFIX,e.bsnnk.com,AdBlock\n - DOMAIN-SUFFIX,e.bvoer.com,AdBlock\n - DOMAIN-SUFFIX,e.cbeif.com,AdBlock\n - DOMAIN-SUFFIX,e.ccunf.com,AdBlock\n - DOMAIN-SUFFIX,e.cdfzcz.com,AdBlock\n - DOMAIN-SUFFIX,e.chfuw.com,AdBlock\n - DOMAIN-SUFFIX,e.cjieh.com,AdBlock\n - DOMAIN-SUFFIX,e.ckikq.com,AdBlock\n - DOMAIN-SUFFIX,e.cn-3drp.com,AdBlock\n - DOMAIN-SUFFIX,e.codlw.com,AdBlock\n - DOMAIN-SUFFIX,e.coenr.com,AdBlock\n - DOMAIN-SUFFIX,e.crashlytics.com,AdBlock\n - DOMAIN-SUFFIX,e.cuomm.com,AdBlock\n - DOMAIN-SUFFIX,e.czggcj.com,AdBlock\n - DOMAIN-SUFFIX,e.daishuxy.com,AdBlock\n - DOMAIN-SUFFIX,e.danrs.com,AdBlock\n - DOMAIN-SUFFIX,e.deimm.com,AdBlock\n - DOMAIN-SUFFIX,e.diogv.com,AdBlock\n - DOMAIN-SUFFIX,e.diupp.com,AdBlock\n - DOMAIN-SUFFIX,e.dnfeu.com,AdBlock\n - DOMAIN-SUFFIX,e.dsjre.com,AdBlock\n - DOMAIN-SUFFIX,e.dunmm.com,AdBlock\n - DOMAIN-SUFFIX,e.dxmci.com,AdBlock\n - DOMAIN-SUFFIX,e.dzairen.com,AdBlock\n - DOMAIN-SUFFIX,e.e7001.com,AdBlock\n - DOMAIN-SUFFIX,e.e70123.com,AdBlock\n - DOMAIN-SUFFIX,e.ehxyz.com,AdBlock\n - DOMAIN-SUFFIX,e.emgwq.com,AdBlock\n - DOMAIN-SUFFIX,e.enjuk.com,AdBlock\n - DOMAIN-SUFFIX,e.ennmt.com,AdBlock\n - DOMAIN-SUFFIX,e.fbaix.com,AdBlock\n - DOMAIN-SUFFIX,e.fbaot.com,AdBlock\n - DOMAIN-SUFFIX,e.fimky.com,AdBlock\n - DOMAIN-SUFFIX,e.fkkse.com,AdBlock\n - DOMAIN-SUFFIX,e.fkogs.com,AdBlock\n - DOMAIN-SUFFIX,e.focuscat.com,AdBlock\n - DOMAIN-SUFFIX,e.fstaw.com,AdBlock\n - DOMAIN-SUFFIX,e.fwjoi.com,AdBlock\n - DOMAIN-SUFFIX,e.fzyda.com,AdBlock\n - DOMAIN-SUFFIX,e.gbieg.com,AdBlock\n - DOMAIN-SUFFIX,e.gglay.com,AdBlock\n - DOMAIN-SUFFIX,e.gxjfh.com,AdBlock\n - DOMAIN-SUFFIX,e.gxkyl.com,AdBlock\n - DOMAIN-SUFFIX,e.harbinbaojia.net,AdBlock\n - DOMAIN-SUFFIX,e.hellomingpian.com,AdBlock\n - DOMAIN-SUFFIX,e.hgrqp.com,AdBlock\n - DOMAIN-SUFFIX,e.hissq.com,AdBlock\n - DOMAIN-SUFFIX,e.hjryl.com,AdBlock\n - DOMAIN-SUFFIX,e.hk7799.net,AdBlock\n - DOMAIN-SUFFIX,e.hkmqp.com,AdBlock\n - DOMAIN-SUFFIX,e.hmhqp.com,AdBlock\n - DOMAIN-SUFFIX,e.hogyp.com,AdBlock\n - DOMAIN-SUFFIX,e.hpzyl.com,AdBlock\n - DOMAIN-SUFFIX,e.htper.com,AdBlock\n - DOMAIN-SUFFIX,e.huaas.com,AdBlock\n - DOMAIN-SUFFIX,e.hunpp.com,AdBlock\n - DOMAIN-SUFFIX,e.huoas.com,AdBlock\n - DOMAIN-SUFFIX,e.hurnt.com,AdBlock\n - DOMAIN-SUFFIX,e.hyzui.com,AdBlock\n - DOMAIN-SUFFIX,e.icyrd.com,AdBlock\n - DOMAIN-SUFFIX,e.iierq.com,AdBlock\n - DOMAIN-SUFFIX,e.infvb.com,AdBlock\n - DOMAIN-SUFFIX,e.irauz.com,AdBlock\n - DOMAIN-SUFFIX,e.irkuj.com,AdBlock\n - DOMAIN-SUFFIX,e.iruad.com,AdBlock\n - DOMAIN-SUFFIX,e.ishowms.com,AdBlock\n - DOMAIN-SUFFIX,e.jdaot.com,AdBlock\n - DOMAIN-SUFFIX,e.jgkto.com,AdBlock\n - DOMAIN-SUFFIX,e.jiaas.com,AdBlock\n - DOMAIN-SUFFIX,e.jiirz.com,AdBlock\n - DOMAIN-SUFFIX,e.jioeg.com,AdBlock\n - DOMAIN-SUFFIX,e.jkert.com,AdBlock\n - DOMAIN-SUFFIX,e.jlkja.com,AdBlock\n - DOMAIN-SUFFIX,e.jltdbyq.com,AdBlock\n - DOMAIN-SUFFIX,e.jnsdkjzs.com,AdBlock\n - DOMAIN-SUFFIX,e.joyxv.com,AdBlock\n - DOMAIN-SUFFIX,e.juyzr.com,AdBlock\n - DOMAIN-SUFFIX,e.jwiyr.com,AdBlock\n - DOMAIN-SUFFIX,e.jxxiangchu.com,AdBlock\n - DOMAIN-SUFFIX,e.kcooy.com,AdBlock\n - DOMAIN-SUFFIX,e.kewro.com,AdBlock\n - DOMAIN-SUFFIX,e.khuoy.com,AdBlock\n - DOMAIN-SUFFIX,e.kjfhe.com,AdBlock\n - DOMAIN-SUFFIX,e.kjhfy.com,AdBlock\n - DOMAIN-SUFFIX,e.kl6636.net,AdBlock\n - DOMAIN-SUFFIX,e.ksttwz.com,AdBlock\n - DOMAIN-SUFFIX,e.kunpp.com,AdBlock\n - DOMAIN-SUFFIX,e.kwjkd.com,AdBlock\n - DOMAIN-SUFFIX,e.kxhie.com,AdBlock\n - DOMAIN-SUFFIX,e.lancedu.com,AdBlock\n - DOMAIN-SUFFIX,e.lfdydk.com,AdBlock\n - DOMAIN-SUFFIX,e.lovezhishou.com,AdBlock\n - DOMAIN-SUFFIX,e.lyjz001.com,AdBlock\n - DOMAIN-SUFFIX,e.lzytt.com,AdBlock\n - DOMAIN-SUFFIX,e.md0z4dh.com,AdBlock\n - DOMAIN-SUFFIX,e.meizhuanghe.com,AdBlock\n - DOMAIN-SUFFIX,e.miaoxinqipei.com,AdBlock\n - DOMAIN-SUFFIX,e.mightiger.net,AdBlock\n - DOMAIN-SUFFIX,e.miiuv.com,AdBlock\n - DOMAIN-SUFFIX,e.mmkvi.com,AdBlock\n - DOMAIN-SUFFIX,e.mozist.com,AdBlock\n - DOMAIN-SUFFIX,e.mqgpo.com,AdBlock\n - DOMAIN-SUFFIX,e.mrsasharingspace.com,AdBlock\n - DOMAIN-SUFFIX,e.mrtuo.com,AdBlock\n - DOMAIN-SUFFIX,e.mushizhubao.com,AdBlock\n - DOMAIN-SUFFIX,e.nduop.com,AdBlock\n - DOMAIN-SUFFIX,e.neijh.com,AdBlock\n - DOMAIN-SUFFIX,e.nejup.com,AdBlock\n - DOMAIN-SUFFIX,e.nernv.com,AdBlock\n - DOMAIN-SUFFIX,e.nexac.com,AdBlock\n - DOMAIN-SUFFIX,e.nfkos.com,AdBlock\n - DOMAIN-SUFFIX,e.nmtouzi.com,AdBlock\n - DOMAIN-SUFFIX,e.nnfiy.com,AdBlock\n - DOMAIN-SUFFIX,e.nwxzs.com,AdBlock\n - DOMAIN-SUFFIX,e.nxypz.com,AdBlock\n - DOMAIN-SUFFIX,e.oesnw.com,AdBlock\n - DOMAIN-SUFFIX,e.okfhn.com,AdBlock\n - DOMAIN-SUFFIX,e.opqsr.com,AdBlock\n - DOMAIN-SUFFIX,e.oyrim.com,AdBlock\n - DOMAIN-SUFFIX,e.pbino.com,AdBlock\n - DOMAIN-SUFFIX,e.picbr.com,AdBlock\n - DOMAIN-SUFFIX,e.plerv.com,AdBlock\n - DOMAIN-SUFFIX,e.pomkl.com,AdBlock\n - DOMAIN-SUFFIX,e.poonscn.com,AdBlock\n - DOMAIN-SUFFIX,e.pubbirdf.com,AdBlock\n - DOMAIN-SUFFIX,e.puooi.com,AdBlock\n - DOMAIN-SUFFIX,e.pwjhg.com,AdBlock\n - DOMAIN-SUFFIX,e.pyerc.com,AdBlock\n - DOMAIN-SUFFIX,e.qiaoyuwang.com,AdBlock\n - DOMAIN-SUFFIX,e.qingzhencai.net,AdBlock\n - DOMAIN-SUFFIX,e.qiyunmuye.com,AdBlock\n - DOMAIN-SUFFIX,e.qsove.com,AdBlock\n - DOMAIN-SUFFIX,e.qvxyz.com,AdBlock\n - DOMAIN-SUFFIX,e.qxfly.com,AdBlock\n - DOMAIN-SUFFIX,e.resmv.com,AdBlock\n - DOMAIN-SUFFIX,e.ricpt.com,AdBlock\n - DOMAIN-SUFFIX,e.rmwdn.com,AdBlock\n - DOMAIN-SUFFIX,e.romgv.com,AdBlock\n - DOMAIN-SUFFIX,e.sanitwealth.com,AdBlock\n - DOMAIN-SUFFIX,e.shenyunkeji.com,AdBlock\n - DOMAIN-SUFFIX,e.sjuqc.com,AdBlock\n - DOMAIN-SUFFIX,e.sosjyx.com,AdBlock\n - DOMAIN-SUFFIX,e.srrux.com,AdBlock\n - DOMAIN-SUFFIX,e.suehy.com,AdBlock\n - DOMAIN-SUFFIX,e.szqifu.com,AdBlock\n - DOMAIN-SUFFIX,e.t71q.com,AdBlock\n - DOMAIN-SUFFIX,e.tdtsd.com,AdBlock\n - DOMAIN-SUFFIX,e.tiantianedu.net,AdBlock\n - DOMAIN-SUFFIX,e.tick0.com,AdBlock\n - DOMAIN-SUFFIX,e.tiojk.com,AdBlock\n - DOMAIN-SUFFIX,e.tuoaa.com,AdBlock\n - DOMAIN-SUFFIX,e.ueram.com,AdBlock\n - DOMAIN-SUFFIX,e.uissm.com,AdBlock\n - DOMAIN-SUFFIX,e.v02u9.cn,AdBlock\n - DOMAIN-SUFFIX,e.vaxyz.com,AdBlock\n - DOMAIN-SUFFIX,e.vbaiu.com,AdBlock\n - DOMAIN-SUFFIX,e.vouky.com,AdBlock\n - DOMAIN-SUFFIX,e.vvocm.com,AdBlock\n - DOMAIN-SUFFIX,e.wcjup.com,AdBlock\n - DOMAIN-SUFFIX,e.weixingshexiangji.net,AdBlock\n - DOMAIN-SUFFIX,e.wikigifth.com,AdBlock\n - DOMAIN-SUFFIX,e.wjhehaofc.com,AdBlock\n - DOMAIN-SUFFIX,e.wkjhd.com,AdBlock\n - DOMAIN-SUFFIX,e.wnxcg.com,AdBlock\n - DOMAIN-SUFFIX,e.wonwg.com,AdBlock\n - DOMAIN-SUFFIX,e.wsxxu.com,AdBlock\n - DOMAIN-SUFFIX,e.x.cn.xtgreat.com,AdBlock\n - DOMAIN-SUFFIX,e.xdkje.com,AdBlock\n - DOMAIN-SUFFIX,e.xeihy.com,AdBlock\n - DOMAIN-SUFFIX,e.xetvb.com,AdBlock\n - DOMAIN-SUFFIX,e.xiangchim0.com,AdBlock\n - DOMAIN-SUFFIX,e.xikdn.com,AdBlock\n - DOMAIN-SUFFIX,e.xkqpco.com.com,AdBlock\n - DOMAIN-SUFFIX,e.xlsschina15.net,AdBlock\n - DOMAIN-SUFFIX,e.xmgysweb.com,AdBlock\n - DOMAIN-SUFFIX,e.xpjis.com,AdBlock\n - DOMAIN-SUFFIX,e.xxkio.com,AdBlock\n - DOMAIN-SUFFIX,e.yageben.com,AdBlock\n - DOMAIN-SUFFIX,e.yangjingbang.net,AdBlock\n - DOMAIN-SUFFIX,e.yerpt.com,AdBlock\n - DOMAIN-SUFFIX,e.yicang8.com,AdBlock\n - DOMAIN-SUFFIX,e.yidulive.net,AdBlock\n - DOMAIN-SUFFIX,e.yingchengtou.com,AdBlock\n - DOMAIN-SUFFIX,e.ynnke.com,AdBlock\n - DOMAIN-SUFFIX,e.yoiur.com,AdBlock\n - DOMAIN-SUFFIX,e.youweiprint.com,AdBlock\n - DOMAIN-SUFFIX,e.ysdangan.com,AdBlock\n - DOMAIN-SUFFIX,e.ysdhe.com,AdBlock\n - DOMAIN-SUFFIX,e.yuxyz.com,AdBlock\n - DOMAIN-SUFFIX,e.ywbwsm.com,AdBlock\n - DOMAIN-SUFFIX,e.yycqc.com,AdBlock\n - DOMAIN-SUFFIX,e.yyeks.com,AdBlock\n - DOMAIN-SUFFIX,e.yyjhf.com,AdBlock\n - DOMAIN-SUFFIX,e.zabxb.com,AdBlock\n - DOMAIN-SUFFIX,e.zhuyuanp.club,AdBlock\n - DOMAIN-SUFFIX,e.zhuyuanp.shop,AdBlock\n - DOMAIN-SUFFIX,e.zhuyuanp.top,AdBlock\n - DOMAIN-SUFFIX,e.zjkdaikuan.com,AdBlock\n - DOMAIN-SUFFIX,e.zkwsdf.com,AdBlock\n - DOMAIN-SUFFIX,e.zunss.com,AdBlock\n - DOMAIN-SUFFIX,e7001.com,AdBlock\n - DOMAIN-SUFFIX,e7002.com,AdBlock\n - DOMAIN-SUFFIX,e7009.com,AdBlock\n - DOMAIN-SUFFIX,e701.net,AdBlock\n - DOMAIN-SUFFIX,e70123.com,AdBlock\n - DOMAIN-SUFFIX,e7015.com,AdBlock\n - DOMAIN-SUFFIX,e704.net,AdBlock\n - DOMAIN-SUFFIX,e705.net,AdBlock\n - DOMAIN-SUFFIX,e706.net,AdBlock\n - DOMAIN-SUFFIX,e708.net,AdBlock\n - DOMAIN-SUFFIX,e719.net,AdBlock\n - DOMAIN-SUFFIX,e9377f.com,AdBlock\n - DOMAIN-SUFFIX,eacash.streamplay.to,AdBlock\n - DOMAIN-SUFFIX,eap.big5.enorth.com.cn,AdBlock\n - DOMAIN-SUFFIX,eap.enorth.com.cn,AdBlock\n - DOMAIN-SUFFIX,easyrecoverychina.com,AdBlock\n - DOMAIN-SUFFIX,ebook.res.meizu.com,AdBlock\n - DOMAIN-SUFFIX,ebp.renren.com,AdBlock\n - DOMAIN-SUFFIX,ec.kejet.net,AdBlock\n - DOMAIN-SUFFIX,eclick.120ask.com,AdBlock\n - DOMAIN-SUFFIX,eclick.360doc.com,AdBlock\n - DOMAIN-SUFFIX,eclick.baidu.com,AdBlock\n - DOMAIN-SUFFIX,eclkspbn.com,AdBlock\n - DOMAIN-SUFFIX,ecma.bdimg.com,AdBlock\n - DOMAIN-SUFFIX,ecmb.bdimg.com,AdBlock\n - DOMAIN-SUFFIX,ecmc.bdimg.com,AdBlock\n - DOMAIN-SUFFIX,ecuc123.net,AdBlock\n - DOMAIN-SUFFIX,ed.aijielang.cn,AdBlock\n - DOMAIN-SUFFIX,ed.sczhilong.cn,AdBlock\n - DOMAIN-SUFFIX,eddong.com,AdBlock\n - DOMAIN-SUFFIX,edesf.xyzxmark.cn,AdBlock\n - DOMAIN-SUFFIX,edge.quantserve.com,AdBlock\n - DOMAIN-SUFFIX,edge.sharethis.com,AdBlock\n - DOMAIN-SUFFIX,edge.yunjiasu.com,AdBlock\n - DOMAIN-SUFFIX,edigitalsurvey.com,AdBlock\n - DOMAIN-SUFFIX,ediuschina.com,AdBlock\n - DOMAIN-SUFFIX,edncui.net,AdBlock\n - DOMAIN-SUFFIX,eduancm.com,AdBlock\n - DOMAIN-SUFFIX,eduzzjy.com,AdBlock\n - DOMAIN-SUFFIX,ee4kdushuba.com,AdBlock\n - DOMAIN-SUFFIX,eee.eh39.co,AdBlock\n - DOMAIN-SUFFIX,eee.kj78.org,AdBlock\n - DOMAIN-SUFFIX,eee.ttyy888.co,AdBlock\n - DOMAIN-SUFFIX,eeee500.com,AdBlock\n - DOMAIN-SUFFIX,eezdx.erc.18183.com,AdBlock\n - DOMAIN-SUFFIX,eff.inte.sogou.com,AdBlock\n - DOMAIN-SUFFIX,effectivemeasure.com,AdBlock\n - DOMAIN-SUFFIX,effectivemeasure.net,AdBlock\n - DOMAIN-SUFFIX,ehd.baike.com,AdBlock\n - DOMAIN-SUFFIX,ehxyz.com,AdBlock\n - DOMAIN-SUFFIX,ein.51yingfa.com,AdBlock\n - DOMAIN-SUFFIX,eiv.baidu.com,AdBlock\n - DOMAIN-SUFFIX,ejzr.golden1.sogou.com,AdBlock\n - DOMAIN-SUFFIX,ekeide.com,AdBlock\n - DOMAIN-SUFFIX,eland.doublemax.net,AdBlock\n - DOMAIN-SUFFIX,em.baidu.com,AdBlock\n - DOMAIN-SUFFIX,emarbox.com,AdBlock\n - DOMAIN-SUFFIX,emss.zjhim.com,AdBlock\n - DOMAIN-SUFFIX,en.shenyun.com,AdBlock\n - DOMAIN-SUFFIX,en.shenyun.org,AdBlock\n - DOMAIN-SUFFIX,engine.lvehaisen.com,AdBlock\n - DOMAIN-SUFFIX,engine.tuia.cn,AdBlock\n - DOMAIN-SUFFIX,ent1.12584.cn,AdBlock\n - DOMAIN-SUFFIX,entry.baidu.com,AdBlock\n - DOMAIN-SUFFIX,e-p4p.163.com,AdBlock\n - DOMAIN-SUFFIX,epernn.cn,AdBlock\n - DOMAIN-SUFFIX,epochtimes.org,AdBlock\n - DOMAIN-SUFFIX,epochweekly.com,AdBlock\n - DOMAIN-SUFFIX,epowernetworktrackerimages.s3.amazonaws.com,AdBlock\n - DOMAIN-SUFFIX,er.dlhygj.com,AdBlock\n - DOMAIN-SUFFIX,erdoscs.com,AdBlock\n - DOMAIN-SUFFIX,erebor.douban.com,AdBlock\n - DOMAIN-SUFFIX,ereg.adobe.com,AdBlock\n - DOMAIN-SUFFIX,ereg.wip3.adobe.com,AdBlock\n - DOMAIN-SUFFIX,ers.baidu.com,AdBlock\n - DOMAIN-SUFFIX,erwqw.zh1155.com,AdBlock\n - DOMAIN-SUFFIX,erwr.ydjskvpd.com,AdBlock\n - DOMAIN-SUFFIX,espn-ak.starwave.com,AdBlock\n - DOMAIN-SUFFIX,esptj.com,AdBlock\n - DOMAIN-SUFFIX,esrpxyahzna.bid,AdBlock\n - DOMAIN-SUFFIX,eteun.cn,AdBlock\n - DOMAIN-SUFFIX,ethod.gzgmjcx.com,AdBlock\n - DOMAIN-SUFFIX,etl.xlmc.sandai.net,AdBlock\n - DOMAIN-SUFFIX,etl.xlmc.sec.miui.com,AdBlock\n - DOMAIN-SUFFIX,eu-gmtdmp.gd1.mookie1.com,AdBlock\n - DOMAIN-SUFFIX,eum-appdynamics.com,AdBlock\n - DOMAIN-SUFFIX,eus.rubiconproject.com,AdBlock\n - DOMAIN-SUFFIX,euwidget.imshopping.com,AdBlock\n - DOMAIN-SUFFIX,eva.ucas.com,AdBlock\n - DOMAIN-SUFFIX,evefashion.cn,AdBlock\n - DOMAIN-SUFFIX,event.ksosoft.com,AdBlock\n - DOMAIN-SUFFIX,eventlog.hd.baofeng.com,AdBlock\n - DOMAIN-SUFFIX,events.kalooga.com,AdBlock\n - DOMAIN-SUFFIX,events.pingan.com,AdBlock\n - DOMAIN-SUFFIX,events-api.outfit7.net,AdBlock\n - DOMAIN-SUFFIX,eviltracker.net,AdBlock\n - DOMAIN-SUFFIX,ew16d.package12.com,AdBlock\n - DOMAIN-SUFFIX,ex.mobmore.com,AdBlock\n - DOMAIN-SUFFIX,ex.puata.info,AdBlock\n - DOMAIN-SUFFIX,exdynsrv.com,AdBlock\n - DOMAIN-SUFFIX,exit.macandbumble.com,AdBlock\n - DOMAIN-SUFFIX,exoclick.com,AdBlock\n - DOMAIN-SUFFIX,exp.17wo.cn,AdBlock\n - DOMAIN-SUFFIX,exp.3g.ifeng.com,AdBlock\n - DOMAIN-SUFFIX,exp.qumi.com,AdBlock\n - DOMAIN-SUFFIX,expo123.net,AdBlock\n - DOMAIN-SUFFIX,ext.theglobalweb.com,AdBlock\n - DOMAIN-SUFFIX,extmoney.i1608.com,AdBlock\n - DOMAIN-SUFFIX,extstat.com,AdBlock\n - DOMAIN-SUFFIX,eyd77s.com,AdBlock\n - DOMAIN-SUFFIX,eye.swfchan.com,AdBlock\n - DOMAIN-SUFFIX,eyouv.cn,AdBlock\n - DOMAIN-SUFFIX,ez33.org.cn,AdBlock\n - DOMAIN-SUFFIX,ezine.oupeng.com,AdBlock\n - DOMAIN-SUFFIX,ezucods.cn,AdBlock\n - DOMAIN-SUFFIX,f.520tingshu.com,AdBlock\n - DOMAIN-SUFFIX,f.doodlemobile.com,AdBlock\n - DOMAIN-SUFFIX,f.f70123.com,AdBlock\n - DOMAIN-SUFFIX,f.fj95560.com,AdBlock\n - DOMAIN-SUFFIX,f.haoxinjaju.com,AdBlock\n - DOMAIN-SUFFIX,f.hongm.com,AdBlock\n - DOMAIN-SUFFIX,f.qcwzx.net.cn,AdBlock\n - DOMAIN-SUFFIX,f.yijikm.com,AdBlock\n - DOMAIN-SUFFIX,f.yueyetiyu.com,AdBlock\n - DOMAIN-SUFFIX,f1.06ps.com,AdBlock\n - DOMAIN-SUFFIX,f1.bizhiku.net,AdBlock\n - DOMAIN-SUFFIX,f1.luoshenbest.cn,AdBlock\n - DOMAIN-SUFFIX,f1.meishichina.com,AdBlock\n - DOMAIN-SUFFIX,f1.p0y.cn,AdBlock\n - DOMAIN-SUFFIX,f1.pig66.com,AdBlock\n - DOMAIN-SUFFIX,f1190.com,AdBlock\n - DOMAIN-SUFFIX,f1c.i.biquge5200.com,AdBlock\n - DOMAIN-SUFFIX,f2.p0y.cn,AdBlock\n - DOMAIN-SUFFIX,f2zd.com,AdBlock\n - DOMAIN-SUFFIX,f3.mi-stat.gslb.mi-idc.com,AdBlock\n - DOMAIN-SUFFIX,f3.vedeh.com,AdBlock\n - DOMAIN-SUFFIX,f5.dfcwg.com,AdBlock\n - DOMAIN-SUFFIX,f5.mtqys.com,AdBlock\n - DOMAIN-SUFFIX,f56g.me,AdBlock\n - DOMAIN-SUFFIX,f6ce.com,AdBlock\n - DOMAIN-SUFFIX,f70123.com,AdBlock\n - DOMAIN-SUFFIX,f8272.com,AdBlock\n - DOMAIN-SUFFIX,fa.163.com,AdBlock\n - DOMAIN-SUFFIX,facebookma.cn,AdBlock\n - DOMAIN-SUFFIX,faggrim.com,AdBlock\n - DOMAIN-SUFFIX,fair.sogou.com,AdBlock\n - DOMAIN-SUFFIX,falundata.com,AdBlock\n - DOMAIN-SUFFIX,falundata.org,AdBlock\n - DOMAIN-SUFFIX,fan.liuxiaoer.com,AdBlock\n - DOMAIN-SUFFIX,fan.twitch.tv,AdBlock\n - DOMAIN-SUFFIX,fancyapi.com,AdBlock\n - DOMAIN-SUFFIX,fanqianbb.com,AdBlock\n - DOMAIN-SUFFIX,fans.bestvogue.com,AdBlock\n - DOMAIN-SUFFIX,fansi365.com,AdBlock\n - DOMAIN-SUFFIX,fan-yong.com,AdBlock\n - DOMAIN-SUFFIX,farm-cn.plista.com,AdBlock\n - DOMAIN-SUFFIX,fastable.com,AdBlock\n - DOMAIN-SUFFIX,fastapi.net,AdBlock\n - DOMAIN-SUFFIX,fastcache.com.cn,AdBlock\n - DOMAIN-SUFFIX,fast-cdn.dianjoy.com,AdBlock\n - DOMAIN-SUFFIX,fastclick.com,AdBlock\n - DOMAIN-SUFFIX,fastclick.net,AdBlock\n - DOMAIN-SUFFIX,fastly.bench.cedexis.com,AdBlock\n - DOMAIN-SUFFIX,fastpopunder.com,AdBlock\n - DOMAIN-SUFFIX,fathionmall.com,AdBlock\n - DOMAIN-SUFFIX,fav.simba.taobao.com,AdBlock\n - DOMAIN-SUFFIX,fb.xk.miui.com,AdBlock\n - DOMAIN-SUFFIX,fbc.ffychb.com,AdBlock\n - DOMAIN-SUFFIX,fccxgjg.com,AdBlock\n - DOMAIN-SUFFIX,fc-feed.cdn.bcebos.com,AdBlock\n - DOMAIN-SUFFIX,fclick.baidu.com,AdBlock\n - DOMAIN-SUFFIX,fcsass.org.cn,AdBlock\n - DOMAIN-SUFFIX,fd.anzhi.com,AdBlock\n - DOMAIN-SUFFIX,fd.qchannel03.cn,AdBlock\n - DOMAIN-SUFFIX,fd7c.com,AdBlock\n - DOMAIN-SUFFIX,fds.api.moji.com,AdBlock\n - DOMAIN-SUFFIX,fe.lea.lycos.co.uk,AdBlock\n - DOMAIN-SUFFIX,fe1-au.imrworldwide.com,AdBlock\n - DOMAIN-SUFFIX,fe2-au.imrworldwide.com,AdBlock\n - DOMAIN-SUFFIX,fe3-au.imrworldwide.com,AdBlock\n - DOMAIN-SUFFIX,fe-au.imrworldwide.com,AdBlock\n - DOMAIN-SUFFIX,feed.baidu.com,AdBlock\n - DOMAIN-SUFFIX,feed.theta.sogou.com,AdBlock\n - DOMAIN-SUFFIX,feedback.whalecloud.com,AdBlock\n - DOMAIN-SUFFIX,feeds.logicbuy.com,AdBlock\n - DOMAIN-SUFFIX,feeds.videosz.com,AdBlock\n - DOMAIN-SUFFIX,fei232.bhzje7ua9.com,AdBlock\n - DOMAIN-SUFFIX,feidalu.com,AdBlock\n - DOMAIN-SUFFIX,feifish66.com,AdBlock\n - DOMAIN-SUFFIX,feih.com.cn,AdBlock\n - DOMAIN-SUFFIX,feitianma.com,AdBlock\n - DOMAIN-SUFFIX,feixin2.com,AdBlock\n - DOMAIN-SUFFIX,fembsflungod.com,AdBlock\n - DOMAIN-SUFFIX,fen.dkdlsj.com,AdBlock\n - DOMAIN-SUFFIX,fengbuy.com,AdBlock\n - DOMAIN-SUFFIX,fenggejiaju.com,AdBlock\n - DOMAIN-SUFFIX,fenqihome.com,AdBlock\n - DOMAIN-SUFFIX,fenvm.com,AdBlock\n - DOMAIN-SUFFIX,fexclick.baidu.com,AdBlock\n - DOMAIN-SUFFIX,ff.nsg.org.ua,AdBlock\n - DOMAIN-SUFFIX,ffb.feihuo.com,AdBlock\n - DOMAIN-SUFFIX,fff.yuyouge.com,AdBlock\n - DOMAIN-SUFFIX,ffhtek.com,AdBlock\n - DOMAIN-SUFFIX,fflsn.com,AdBlock\n - DOMAIN-SUFFIX,ffre.ffrepair.com,AdBlock\n - DOMAIN-SUFFIX,ffychb.com,AdBlock\n - DOMAIN-SUFFIX,fge9vbrzwt.bid,AdBlock\n - DOMAIN-SUFFIX,fghm.ga25.com,AdBlock\n - DOMAIN-SUFFIX,fghmc.ga25.com,AdBlock\n - DOMAIN-SUFFIX,fghmimg.ga25.com,AdBlock\n - DOMAIN-SUFFIX,fgmtv.org,AdBlock\n - DOMAIN-SUFFIX,file.bmob.cn,AdBlock\n - DOMAIN-SUFFIX,files2.sogou.com,AdBlock\n - DOMAIN-SUFFIX,fimserve.ign.com,AdBlock\n - DOMAIN-SUFFIX,findicons.com,AdBlock\n - DOMAIN-SUFFIX,finding.hardwareheaven.com,AdBlock\n - DOMAIN-SUFFIX,findnsave.idahostatesman.com,AdBlock\n - DOMAIN-SUFFIX,finead.cn,AdBlock\n - DOMAIN-SUFFIX,fips.uimserv.net,AdBlock\n - DOMAIN-SUFFIX,firefang.cn,AdBlock\n - DOMAIN-SUFFIX,fjkst.com,AdBlock\n - DOMAIN-SUFFIX,fjlqqc.com,AdBlock\n - DOMAIN-SUFFIX,fjmeyer.com,AdBlock\n - DOMAIN-SUFFIX,fkku194.com,AdBlock\n - DOMAIN-SUFFIX,flash.2144.com,AdBlock\n - DOMAIN-SUFFIX,flashtalking.com,AdBlock\n - DOMAIN-SUFFIX,flowcodeapp.com,AdBlock\n - DOMAIN-SUFFIX,flstudiochina.com,AdBlock\n - DOMAIN-SUFFIX,flurry.cachefly.net,AdBlock\n - DOMAIN-SUFFIX,flurry.com,AdBlock\n - DOMAIN-SUFFIX,flux.faloo.com,AdBlock\n - DOMAIN-SUFFIX,flv.dotmore.com.tw,AdBlock\n - DOMAIN-SUFFIX,flv.ytshuirun.com,AdBlock\n - DOMAIN-SUFFIX,flwja.com,AdBlock\n - DOMAIN-SUFFIX,fm.p0y.cn,AdBlock\n - DOMAIN-SUFFIX,fmgoal.com,AdBlock\n - DOMAIN-SUFFIX,fnkjj.com,AdBlock\n - DOMAIN-SUFFIX,focuscat.com,AdBlock\n - DOMAIN-SUFFIX,focusprolight.com,AdBlock\n - DOMAIN-SUFFIX,formysql.com,AdBlock\n - DOMAIN-SUFFIX,fota4.adups.cn,AdBlock\n - DOMAIN-SUFFIX,fotao9.com,AdBlock\n - DOMAIN-SUFFIX,founseezb.cn,AdBlock\n - DOMAIN-SUFFIX,fozhu.rrsdl.com,AdBlock\n - DOMAIN-SUFFIX,fp.fraudmetrix.cn,AdBlock\n - DOMAIN-SUFFIX,fpb.51edu.com,AdBlock\n - DOMAIN-SUFFIX,fpb.kuhou.com,AdBlock\n - DOMAIN-SUFFIX,fpb.mn586.com,AdBlock\n - DOMAIN-SUFFIX,fpbbdx1.51240.com,AdBlock\n - DOMAIN-SUFFIX,fpbjiansuo.mn586.com,AdBlock\n - DOMAIN-SUFFIX,fpdownload.macromedia.com,AdBlock\n - DOMAIN-SUFFIX,fptest.fraudmetrix.cn,AdBlock\n - DOMAIN-SUFFIX,fqtra.com,AdBlock\n - DOMAIN-SUFFIX,frame.enet.com.cn,AdBlock\n - DOMAIN-SUFFIX,fraudmetrix.cn,AdBlock\n - DOMAIN-SUFFIX,frdhq.cn,AdBlock\n - DOMAIN-SUFFIX,free.aol.com,AdBlock\n - DOMAIN-SUFFIX,freecodecs.us.intellitxt.com,AdBlock\n - DOMAIN-SUFFIX,freedrive.cn,AdBlock\n - DOMAIN-SUFFIX,freexxxvideoclip.aebn.net,AdBlock\n - DOMAIN-SUFFIX,fs.uc.nearme.com.cn,AdBlock\n - DOMAIN-SUFFIX,fsjsp.com,AdBlock\n - DOMAIN-SUFFIX,fsr.lenovomm.com,AdBlock\n - DOMAIN-SUFFIX,fst360.com,AdBlock\n - DOMAIN-SUFFIX,fs-uc-nearme-com-cn.oss-cn-hangzhou.aliyuncs.com,AdBlock\n - DOMAIN-SUFFIX,fsyzcs.com,AdBlock\n - DOMAIN-SUFFIX,ft.moad.cn,AdBlock\n - DOMAIN-SUFFIX,ft.pnop.com,AdBlock\n - DOMAIN-SUFFIX,fthcz.com,AdBlock\n - DOMAIN-SUFFIX,fu68.com,AdBlock\n - DOMAIN-SUFFIX,fucnm.com,AdBlock\n - DOMAIN-SUFFIX,fujianryt.com,AdBlock\n - DOMAIN-SUFFIX,fun.ynet.com,AdBlock\n - DOMAIN-SUFFIX,funshion.net.cn,AdBlock\n - DOMAIN-SUFFIX,fus.lenovomm.com,AdBlock\n - DOMAIN-SUFFIX,fusion.qq.com,AdBlock\n - DOMAIN-SUFFIX,fv99.com,AdBlock\n - DOMAIN-SUFFIX,fw.adsafeprotected.com,AdBlock\n - DOMAIN-SUFFIX,fw.vpon.com,AdBlock\n - DOMAIN-SUFFIX,fwmrm.net,AdBlock\n - DOMAIN-SUFFIX,fwt0.com,AdBlock\n - DOMAIN-SUFFIX,fxc.aiquxs.com,AdBlock\n - DOMAIN-SUFFIX,fxmacd.com,AdBlock\n - DOMAIN-SUFFIX,fxtducb.cn,AdBlock\n - DOMAIN-SUFFIX,fxxgw.com,AdBlock\n - DOMAIN-SUFFIX,fych.uranus.sogou.com,AdBlock\n - DOMAIN-SUFFIX,fydgold132.com,AdBlock\n - DOMAIN-SUFFIX,fytza.cn,AdBlock\n - DOMAIN-SUFFIX,fz863.com,AdBlock\n - DOMAIN-SUFFIX,fzz.cloud.1234507.com,AdBlock\n - DOMAIN-SUFFIX,fzz.shgqjr.com,AdBlock\n - DOMAIN-SUFFIX,g.163.com,AdBlock\n - DOMAIN-SUFFIX,g.51network.com,AdBlock\n - DOMAIN-SUFFIX,g.6sfg.com,AdBlock\n - DOMAIN-SUFFIX,g.ad8.cc,AdBlock\n - DOMAIN-SUFFIX,g.aligames.com,AdBlock\n - DOMAIN-SUFFIX,g.baidu.com,AdBlock\n - DOMAIN-SUFFIX,g.bitauto.com,AdBlock\n - DOMAIN-SUFFIX,g.brothersoft.com,AdBlock\n - DOMAIN-SUFFIX,g.chuiyao.com,AdBlock\n - DOMAIN-SUFFIX,g.d.yoyi.tv,AdBlock\n - DOMAIN-SUFFIX,g.daman.cc,AdBlock\n - DOMAIN-SUFFIX,g.f11w.com,AdBlock\n - DOMAIN-SUFFIX,g.f5gh.com,AdBlock\n - DOMAIN-SUFFIX,g.gridsum.com,AdBlock\n - DOMAIN-SUFFIX,g.haluoha.com,AdBlock\n - DOMAIN-SUFFIX,g.hsw.cn,AdBlock\n - DOMAIN-SUFFIX,g.koowo.com,AdBlock\n - DOMAIN-SUFFIX,g.mnw.cn,AdBlock\n - DOMAIN-SUFFIX,g.ousns.net,AdBlock\n - DOMAIN-SUFFIX,g.rs.yoyi.com.cn,AdBlock\n - DOMAIN-SUFFIX,g.s8dj.com,AdBlock\n - DOMAIN-SUFFIX,g.szdn1ms.com,AdBlock\n - DOMAIN-SUFFIX,g.usingde.com,AdBlock\n - DOMAIN-SUFFIX,g.w5b454.com,AdBlock\n - DOMAIN-SUFFIX,g.wan.2345.com,AdBlock\n - DOMAIN-SUFFIX,g.wan.douyu.com,AdBlock\n - DOMAIN-SUFFIX,g.wrating.com,AdBlock\n - DOMAIN-SUFFIX,g.x.cn.xtgreat.com,AdBlock\n - DOMAIN-SUFFIX,g.x.evolife.cn,AdBlock\n - DOMAIN-SUFFIX,g.yccdn.com,AdBlock\n - DOMAIN-SUFFIX,g.zx-jsp.com,AdBlock\n - DOMAIN-SUFFIX,g1.0573ren.com,AdBlock\n - DOMAIN-SUFFIX,g1.08160.cn,AdBlock\n - DOMAIN-SUFFIX,g1.163.com,AdBlock\n - DOMAIN-SUFFIX,g1.taijuba.com,AdBlock\n - DOMAIN-SUFFIX,g1c5.com,AdBlock\n - DOMAIN-SUFFIX,g1f5.com,AdBlock\n - DOMAIN-SUFFIX,g2.ousns.net,AdBlock\n - DOMAIN-SUFFIX,g3.iqilu.com,AdBlock\n - DOMAIN-SUFFIX,g4.iqilu.com,AdBlock\n - DOMAIN-SUFFIX,g9s.sgzs999.com,AdBlock\n - DOMAIN-SUFFIX,gad.kugou.com,AdBlock\n - DOMAIN-SUFFIX,gadwhy.com,AdBlock\n - DOMAIN-SUFFIX,gafxa.code.mytanwan.com,AdBlock\n - DOMAIN-SUFFIX,galaxy.sogoucdn.com,AdBlock\n - DOMAIN-SUFFIX,game.9xzj.com,AdBlock\n - DOMAIN-SUFFIX,game.baichuanhd.cn,AdBlock\n - DOMAIN-SUFFIX,game.html5.qq.com,AdBlock\n - DOMAIN-SUFFIX,game.kugou.com,AdBlock\n - DOMAIN-SUFFIX,game.kuwo.cn,AdBlock\n - DOMAIN-SUFFIX,game.qidian.com,AdBlock\n - DOMAIN-SUFFIX,game.res.meizu.com,AdBlock\n - DOMAIN-SUFFIX,game.rising.cn,AdBlock\n - DOMAIN-SUFFIX,game.subway.uu.cc,AdBlock\n - DOMAIN-SUFFIX,game.weibo.cn,AdBlock\n - DOMAIN-SUFFIX,game.weibo.com,AdBlock\n - DOMAIN-SUFFIX,gamead.swjoy.com,AdBlock\n - DOMAIN-SUFFIX,gameads.digyourowngrave.com,AdBlock\n - DOMAIN-SUFFIX,gamebox.kugou.com,AdBlock\n - DOMAIN-SUFFIX,game-res.meizu.com,AdBlock\n - DOMAIN-SUFFIX,ganjituiguang.ganji.com,AdBlock\n - DOMAIN-SUFFIX,gao.ynet.com,AdBlock\n - DOMAIN-SUFFIX,gas.data.pplive.com,AdBlock\n - DOMAIN-SUFFIX,gateway.fortunelounge.com,AdBlock\n - DOMAIN-SUFFIX,gateways.s3.amazonaws.com,AdBlock\n - DOMAIN-SUFFIX,gb.corp.163.com,AdBlock\n - DOMAIN-SUFFIX,gc.keefung-zs.com,AdBlock\n - DOMAIN-SUFFIX,gcapi.sy.kugou.com,AdBlock\n - DOMAIN-SUFFIX,gclick.cn,AdBlock\n - DOMAIN-SUFFIX,gcs1.cn,AdBlock\n - DOMAIN-SUFFIX,gd.cnhange.cn,AdBlock\n - DOMAIN-SUFFIX,gd.jqgc.com,AdBlock\n - DOMAIN-SUFFIX,gd.vodtw.com,AdBlock\n - DOMAIN-SUFFIX,gdbly.com,AdBlock\n - DOMAIN-SUFFIX,gdgy56.com,AdBlock\n - DOMAIN-SUFFIX,gdskywings.com,AdBlock\n - DOMAIN-SUFFIX,gdsqwy.org,AdBlock\n - DOMAIN-SUFFIX,gdyn.cnn.com,AdBlock\n - DOMAIN-SUFFIX,ge95.com,AdBlock\n - DOMAIN-SUFFIX,geili.co,AdBlock\n - DOMAIN-SUFFIX,geiyujieda.com,AdBlock\n - DOMAIN-SUFFIX,gemini.yahoo.com,AdBlock\n - DOMAIN-SUFFIX,gen.alicdn.com,AdBlock\n - DOMAIN-SUFFIX,gentags.com,AdBlock\n - DOMAIN-SUFFIX,geo.cliphunter.com,AdBlock\n - DOMAIN-SUFFIX,geo.connexionsecure.com,AdBlock\n - DOMAIN-SUFFIX,geo.frtya.com,AdBlock\n - DOMAIN-SUFFIX,geo.frtyd.com,AdBlock\n - DOMAIN-SUFFIX,geo.gridsumdissector.com,AdBlock\n - DOMAIN-SUFFIX,geo.moatads.com,AdBlock\n - DOMAIN-SUFFIX,geo.yahoo.com,AdBlock\n - DOMAIN-SUFFIX,geo2.adobe.com,AdBlock\n - DOMAIN-SUFFIX,geobanner.alt.com,AdBlock\n - DOMAIN-SUFFIX,geobanner.friendfinder.com,AdBlock\n - DOMAIN-SUFFIX,geobanner.passion.com,AdBlock\n - DOMAIN-SUFFIX,geobanner.socialflirt.com,AdBlock\n - DOMAIN-SUFFIX,geoshopping.nzherald.co.nz,AdBlock\n - DOMAIN-SUFFIX,geryi.com,AdBlock\n - DOMAIN-SUFFIX,get.thefile.me,AdBlock\n - DOMAIN-SUFFIX,get3.adobe.com,AdBlock\n - DOMAIN-SUFFIX,getnormalizedurl.com,AdBlock\n - DOMAIN-SUFFIX,gewuwen.com,AdBlock\n - DOMAIN-SUFFIX,gf108.com,AdBlock\n - DOMAIN-SUFFIX,gf1352.com,AdBlock\n - DOMAIN-SUFFIX,gfd80.com,AdBlock\n - DOMAIN-SUFFIX,gfh.ahfzly.com,AdBlock\n - DOMAIN-SUFFIX,gfx.infomine.com,AdBlock\n - DOMAIN-SUFFIX,gg.0598yu.com,AdBlock\n - DOMAIN-SUFFIX,gg.5173.com,AdBlock\n - DOMAIN-SUFFIX,gg.51cto.com,AdBlock\n - DOMAIN-SUFFIX,gg.amblrgg.live,AdBlock\n - DOMAIN-SUFFIX,gg.anqu.com,AdBlock\n - DOMAIN-SUFFIX,gg.blueidea.com,AdBlock\n - DOMAIN-SUFFIX,gg.caixin.com,AdBlock\n - DOMAIN-SUFFIX,gg.cs090.com,AdBlock\n - DOMAIN-SUFFIX,gg.dsxdn.com,AdBlock\n - DOMAIN-SUFFIX,gg.gao7.com,AdBlock\n - DOMAIN-SUFFIX,gg.haianw.com,AdBlock\n - DOMAIN-SUFFIX,gg.huangye88.com,AdBlock\n - DOMAIN-SUFFIX,gg.jkmeishi.com,AdBlock\n - DOMAIN-SUFFIX,gg.kugou.com,AdBlock\n - DOMAIN-SUFFIX,gg.meitu.com,AdBlock\n - DOMAIN-SUFFIX,gg.ptfish.com,AdBlock\n - DOMAIN-SUFFIX,gg.sonhoo.com,AdBlock\n - DOMAIN-SUFFIX,gg.stargame.com,AdBlock\n - DOMAIN-SUFFIX,gg.uuu9.com,AdBlock\n - DOMAIN-SUFFIX,gg.vidown.cn,AdBlock\n - DOMAIN-SUFFIX,gg.xywy.com,AdBlock\n - DOMAIN-SUFFIX,gg.yxdown.com,AdBlock\n - DOMAIN-SUFFIX,gg.zhongyao1.com,AdBlock\n - DOMAIN-SUFFIX,gg0376.com,AdBlock\n - DOMAIN-SUFFIX,gg1.yszyz.com,AdBlock\n - DOMAIN-SUFFIX,gg2.51cto.com,AdBlock\n - DOMAIN-SUFFIX,gg2.dss9927.com,AdBlock\n - DOMAIN-SUFFIX,gg3.51cto.com,AdBlock\n - DOMAIN-SUFFIX,gg570.com,AdBlock\n - DOMAIN-SUFFIX,gg86.pinggu.org,AdBlock\n - DOMAIN-SUFFIX,gg8888.cnfol.com,AdBlock\n - DOMAIN-SUFFIX,ggb.douguo.com,AdBlock\n - DOMAIN-SUFFIX,ggcode.2345.com,AdBlock\n - DOMAIN-SUFFIX,ggdoubi.com,AdBlock\n - DOMAIN-SUFFIX,ggg.zj.com,AdBlock\n - DOMAIN-SUFFIX,ggle.lywf.me,AdBlock\n - DOMAIN-SUFFIX,ggmm777.com,AdBlock\n - DOMAIN-SUFFIX,ggmmqq.com,AdBlock\n - DOMAIN-SUFFIX,ggr.yxdown.com,AdBlock\n - DOMAIN-SUFFIX,ggs.myzaker.com,AdBlock\n - DOMAIN-SUFFIX,ggw.gusuwang.com,AdBlock\n - DOMAIN-SUFFIX,ggw.watertu.com,AdBlock\n - DOMAIN-SUFFIX,ggxt.net,AdBlock\n - DOMAIN-SUFFIX,gi.xi.gxabj.com,AdBlock\n - DOMAIN-SUFFIX,gif.lu.sogoucdn.com,AdBlock\n - DOMAIN-SUFFIX,gimg.baidu.com,AdBlock\n - DOMAIN-SUFFIX,gimg.bitauto.com,AdBlock\n - DOMAIN-SUFFIX,girlcc.cc,AdBlock\n - DOMAIN-SUFFIX,gj500.com,AdBlock\n - DOMAIN-SUFFIX,gjghy.com,AdBlock\n - DOMAIN-SUFFIX,gjreg.code.weddingeeos.com,AdBlock\n - DOMAIN-SUFFIX,glasszz.com,AdBlock\n - DOMAIN-SUFFIX,gload.adhood.com,AdBlock\n - DOMAIN-SUFFIX,global.msads.net,AdBlock\n - DOMAIN-SUFFIX,global.ymtracking.com,AdBlock\n - DOMAIN-SUFFIX,gm682.com,AdBlock\n - DOMAIN-SUFFIX,gma1.com,AdBlock\n - DOMAIN-SUFFIX,gmota.g188.net,AdBlock\n - DOMAIN-SUFFIX,gmtdmp.mookie1.com,AdBlock\n - DOMAIN-SUFFIX,go.gogolm.xyz,AdBlock\n - DOMAIN-SUFFIX,go.gotourl.xyz,AdBlock\n - DOMAIN-SUFFIX,go.gotourls.bid,AdBlock\n - DOMAIN-SUFFIX,go.hangzhou.com.cn,AdBlock\n - DOMAIN-SUFFIX,go.onclasrv.com,AdBlock\n - DOMAIN-SUFFIX,go.util.zlibs.com,AdBlock\n - DOMAIN-SUFFIX,godloveme.cn,AdBlock\n - DOMAIN-SUFFIX,gog9.qzdfc.com,AdBlock\n - DOMAIN-SUFFIX,go-mpulse.net,AdBlock\n - DOMAIN-SUFFIX,good.ta80.com,AdBlock\n - DOMAIN-SUFFIX,googleadsserving.cn,AdBlock\n - DOMAIN-SUFFIX,googleads.g.doubleclick.net,AdBlock\n - DOMAIN-SUFFIX,googlecommerce.com,AdBlock\n - DOMAIN-SUFFIX,googlesyndication.com,AdBlock\n - DOMAIN-SUFFIX,goolpter.com,AdBlock\n - DOMAIN-SUFFIX,gopig.io,AdBlock\n - DOMAIN-SUFFIX,gorgon.youdao.com,AdBlock\n - DOMAIN-SUFFIX,gosquared.com,AdBlock\n - DOMAIN-SUFFIX,goto.sogou.com,AdBlock\n - DOMAIN-SUFFIX,goto.www.iciba.com,AdBlock\n - DOMAIN-SUFFIX,gotourl.xyz,AdBlock\n - DOMAIN-SUFFIX,goufanli100.com,AdBlock\n - DOMAIN-SUFFIX,gouwubang.com,AdBlock\n - DOMAIN-SUFFIX,gouzhibao.cn,AdBlock\n - DOMAIN-SUFFIX,govgift.com,AdBlock\n - DOMAIN-SUFFIX,govids.net,AdBlock\n - DOMAIN-SUFFIX,gp.jstv.com,AdBlock\n - DOMAIN-SUFFIX,gpydym.cn,AdBlock\n - DOMAIN-SUFFIX,gqswg.com,AdBlock\n - DOMAIN-SUFFIX,grand.ele.me,AdBlock\n - DOMAIN-SUFFIX,green.erne.co,AdBlock\n - DOMAIN-SUFFIX,greenhouseglobal.cn,AdBlock\n - DOMAIN-SUFFIX,greenxfs.down.123ch.cn,AdBlock\n - DOMAIN-SUFFIX,gridsum.com,AdBlock\n - DOMAIN-SUFFIX,gridsumdissector.cn,AdBlock\n - DOMAIN-SUFFIX,gridsumdissector.com,AdBlock\n - DOMAIN-SUFFIX,groupa.onlylady.com,AdBlock\n - DOMAIN-SUFFIX,growingio.com,AdBlock\n - DOMAIN-SUFFIX,gs307.com,AdBlock\n - DOMAIN-SUFFIX,gso0.com,AdBlock\n - DOMAIN-SUFFIX,gstat.bitauto.com,AdBlock\n - DOMAIN-SUFFIX,gt.yy.com,AdBlock\n - DOMAIN-SUFFIX,gt4ec.net,AdBlock\n - DOMAIN-SUFFIX,gtags.net,AdBlock\n - DOMAIN-SUFFIX,gtmucs.cn,AdBlock\n - DOMAIN-SUFFIX,gu.qlogo.cn,AdBlock\n - DOMAIN-SUFFIX,guang.lesports.com,AdBlock\n - DOMAIN-SUFFIX,guang.sdsgwy.com,AdBlock\n - DOMAIN-SUFFIX,guangzhuiyuan.com,AdBlock\n - DOMAIN-SUFFIX,guangzizai.com,AdBlock\n - DOMAIN-SUFFIX,guanjia.baidu.com,AdBlock\n - DOMAIN-SUFFIX,guduopu.com,AdBlock\n - DOMAIN-SUFFIX,guess.h.qhimg.com,AdBlock\n - DOMAIN-SUFFIX,guestworld.tripod.lycos.com,AdBlock\n - DOMAIN-SUFFIX,gugulonger.cn,AdBlock\n - DOMAIN-SUFFIX,guidashu.com,AdBlock\n - DOMAIN-SUFFIX,guitarpro.cc,AdBlock\n - DOMAIN-SUFFIX,gum.criteo.com,AdBlock\n - DOMAIN-SUFFIX,guohead.com,AdBlock\n - DOMAIN-SUFFIX,guomob.com,AdBlock\n - DOMAIN-SUFFIX,guoshennet.com,AdBlock\n - DOMAIN-SUFFIX,gw5.push.mcp.weibo.cn,AdBlock\n - DOMAIN-SUFFIX,gw6.push.mcp.weibo.cn,AdBlock\n - DOMAIN-SUFFIX,gw630.com,AdBlock\n - DOMAIN-SUFFIX,gx38.cn,AdBlock\n - DOMAIN-SUFFIX,gxdhgb.com,AdBlock\n - DOMAIN-SUFFIX,gxe.husky.sogou.com,AdBlock\n - DOMAIN-SUFFIX,gyca9f.dahuangcheng.cn,AdBlock\n - DOMAIN-SUFFIX,gydag.com,AdBlock\n - DOMAIN-SUFFIX,gyrtg.com,AdBlock\n - DOMAIN-SUFFIX,gz.hxdaka.com,AdBlock\n - DOMAIN-SUFFIX,gz00005.top,AdBlock\n - DOMAIN-SUFFIX,gzktpf.com,AdBlock\n - DOMAIN-SUFFIX,gzlykj.cn,AdBlock\n - DOMAIN-SUFFIX,gzmjnx.cn,AdBlock\n - DOMAIN-SUFFIX,gzqudou.com,AdBlock\n - DOMAIN-SUFFIX,h.canmg.cn,AdBlock\n - DOMAIN-SUFFIX,h.holder.com.ua,AdBlock\n - DOMAIN-SUFFIX,h.irs01.com,AdBlock\n - DOMAIN-SUFFIX,h.laojiayoufang.com,AdBlock\n - DOMAIN-SUFFIX,h.msn.com,AdBlock\n - DOMAIN-SUFFIX,h.sora.yoyi.com.cn,AdBlock\n - DOMAIN-SUFFIX,h01.hotrank.com.tw,AdBlock\n - DOMAIN-SUFFIX,h1.18sd.cn,AdBlock\n - DOMAIN-SUFFIX,h2.18sd.cn,AdBlock\n - DOMAIN-SUFFIX,h5.holalauncher.com,AdBlock\n - DOMAIN-SUFFIX,h5.jiumaster.com,AdBlock\n - DOMAIN-SUFFIX,h5.pk1179.com,AdBlock\n - DOMAIN-SUFFIX,h5.super-dreamers.com,AdBlock\n - DOMAIN-SUFFIX,h5.taihao.cc,AdBlock\n - DOMAIN-SUFFIX,h5-api.feiersmart.com,AdBlock\n - DOMAIN-SUFFIX,h8.bec.com,AdBlock\n - DOMAIN-SUFFIX,h9377c.com,AdBlock\n - DOMAIN-SUFFIX,haitaoad.nosdn.127.net,AdBlock\n - DOMAIN-SUFFIX,haiwai-ic.ksosoft.com,AdBlock\n - DOMAIN-SUFFIX,haiwengji.net,AdBlock\n - DOMAIN-SUFFIX,haiyunpush.com,AdBlock\n - DOMAIN-SUFFIX,hanju18.net,AdBlock\n - DOMAIN-SUFFIX,hao.7654.com,AdBlock\n - DOMAIN-SUFFIX,hao.qquu8.com,AdBlock\n - DOMAIN-SUFFIX,hao.tiandi.com,AdBlock\n - DOMAIN-SUFFIX,hao.uc.cn,AdBlock\n - DOMAIN-SUFFIX,hao123.xywy.com,AdBlock\n - DOMAIN-SUFFIX,hao123rt.com,AdBlock\n - DOMAIN-SUFFIX,hao549.com,AdBlock\n - DOMAIN-SUFFIX,hao61.net,AdBlock\n - DOMAIN-SUFFIX,hao916.com,AdBlock\n - DOMAIN-SUFFIX,hao934.com,AdBlock\n - DOMAIN-SUFFIX,haoghost.com,AdBlock\n - DOMAIN-SUFFIX,haohaowan8.com,AdBlock\n - DOMAIN-SUFFIX,haolew.com,AdBlock\n - DOMAIN-SUFFIX,haoshengtoys.com,AdBlock\n - DOMAIN-SUFFIX,haostat.qihoo.com,AdBlock\n - DOMAIN-SUFFIX,hapic1.jhkxwl.com,AdBlock\n - DOMAIN-SUFFIX,hascosafety.com,AdBlock\n - DOMAIN-SUFFIX,hats.haibao.cn,AdBlock\n - DOMAIN-SUFFIX,hbalx.cn,AdBlock\n - DOMAIN-SUFFIX,hbdt.luomi.com,AdBlock\n - DOMAIN-SUFFIX,hblinwei.com,AdBlock\n - DOMAIN-SUFFIX,hbngfy.com,AdBlock\n - DOMAIN-SUFFIX,hbyyzm.com,AdBlock\n - DOMAIN-SUFFIX,hc.baidu.com,AdBlock\n - DOMAIN-SUFFIX,hccms.com.cn,AdBlock\n - DOMAIN-SUFFIX,hcreditx.com,AdBlock\n - DOMAIN-SUFFIX,hd.jiedaibao.com,AdBlock\n - DOMAIN-SUFFIX,hd.ylddq.com,AdBlock\n - DOMAIN-SUFFIX,hda.maxli.cn,AdBlock\n - DOMAIN-SUFFIX,hdad.baike.com,AdBlock\n - DOMAIN-SUFFIX,hdb.maxli.cn,AdBlock\n - DOMAIN-SUFFIX,hdggcdn.bayimob.com,AdBlock\n - DOMAIN-SUFFIX,hdhkwl.com,AdBlock\n - DOMAIN-SUFFIX,hdj.baidu.com,AdBlock\n - DOMAIN-SUFFIX,he2d.com,AdBlock\n - DOMAIN-SUFFIX,health1.12584.cn,AdBlock\n - DOMAIN-SUFFIX,heavenmedia.v3g4s.com,AdBlock\n - DOMAIN-SUFFIX,hechaocheng.cn,AdBlock\n - DOMAIN-SUFFIX,heefwozhlxgz.com,AdBlock\n - DOMAIN-SUFFIX,hefan365.com,AdBlock\n - DOMAIN-SUFFIX,heib10.top,AdBlock\n - DOMAIN-SUFFIX,heib12.top,AdBlock\n - DOMAIN-SUFFIX,heimo.rrsdl.com,AdBlock\n - DOMAIN-SUFFIX,hejban.youwatch.org,AdBlock\n - DOMAIN-SUFFIX,hejingroup.cn,AdBlock\n - DOMAIN-SUFFIX,help.baotangwang.cn,AdBlock\n - DOMAIN-SUFFIX,help.yunaq.com,AdBlock\n - DOMAIN-SUFFIX,hesxz.com,AdBlock\n - DOMAIN-SUFFIX,heyzap.com,AdBlock\n - DOMAIN-SUFFIX,hfjuki.com,AdBlock\n - DOMAIN-SUFFIX,hfsteel.net,AdBlock\n - DOMAIN-SUFFIX,hg417.bet,AdBlock\n - DOMAIN-SUFFIX,hg89038.com,AdBlock\n - DOMAIN-SUFFIX,hg89068.com,AdBlock\n - DOMAIN-SUFFIX,hg89078.com,AdBlock\n - DOMAIN-SUFFIX,hgame.com,AdBlock\n - DOMAIN-SUFFIX,hh6666.com,AdBlock\n - DOMAIN-SUFFIX,hhlian.com,AdBlock\n - DOMAIN-SUFFIX,hhly88.com,AdBlock\n - DOMAIN-SUFFIX,hhppyt.com,AdBlock\n - DOMAIN-SUFFIX,hhqda.pop.t5yx.cn,AdBlock\n - DOMAIN-SUFFIX,hi686.com,AdBlock\n - DOMAIN-SUFFIX,hi760.com,AdBlock\n - DOMAIN-SUFFIX,hi9377.com,AdBlock\n - DOMAIN-SUFFIX,hiad.myweb.hinet.net,AdBlock\n - DOMAIN-SUFFIX,hiad.vmall.com,AdBlock\n - DOMAIN-SUFFIX,higame123.com,AdBlock\n - DOMAIN-SUFFIX,hilltopads.net,AdBlock\n - DOMAIN-SUFFIX,himandy.com,AdBlock\n - DOMAIN-SUFFIX,hipersushiads.com,AdBlock\n - DOMAIN-SUFFIX,histats.com,AdBlock\n - DOMAIN-SUFFIX,hit.webcentre.lycos.co.uk,AdBlock\n - DOMAIN-SUFFIX,hitlog2.chosun.com,AdBlock\n - DOMAIN-SUFFIX,hitslink.com,AdBlock\n - DOMAIN-SUFFIX,hivecn.cn,AdBlock\n - DOMAIN-SUFFIX,hivedata.cc,AdBlock\n - DOMAIN-SUFFIX,hjc1990.com,AdBlock\n - DOMAIN-SUFFIX,hk.jtsh123.com,AdBlock\n - DOMAIN-SUFFIX,hk.napi.ucweb.com,AdBlock\n - DOMAIN-SUFFIX,hk9600.com,AdBlock\n - DOMAIN-SUFFIX,hk-cdn.effectivemeasure.net,AdBlock\n - DOMAIN-SUFFIX,hkfuy.com,AdBlock\n - DOMAIN-SUFFIX,hl.kuzu.com,AdBlock\n - DOMAIN-SUFFIX,hl.quw18.com,AdBlock\n - DOMAIN-SUFFIX,hl2rcv.adobe.com,AdBlock\n - DOMAIN-SUFFIX,hldwmly.com,AdBlock\n - DOMAIN-SUFFIX,hlrcv.stage.adobe.com,AdBlock\n - DOMAIN-SUFFIX,hmp33.com,AdBlock\n - DOMAIN-SUFFIX,hmttoly.com,AdBlock\n - DOMAIN-SUFFIX,hmyangshengji.com,AdBlock\n - DOMAIN-SUFFIX,hnasd.com,AdBlock\n - DOMAIN-SUFFIX,hnctsm.com,AdBlock\n - DOMAIN-SUFFIX,hndiyikj.com,AdBlock\n - DOMAIN-SUFFIX,hnxxjn.com,AdBlock\n - DOMAIN-SUFFIX,hnyny.com,AdBlock\n - DOMAIN-SUFFIX,hoisin.coocaatv.com,AdBlock\n - DOMAIN-SUFFIX,home520.com,AdBlock\n - DOMAIN-SUFFIX,hoplink.ksosoft.com,AdBlock\n - DOMAIN-SUFFIX,hosting.miarroba.info,AdBlock\n - DOMAIN-SUFFIX,hot.browser.miui.com,AdBlock\n - DOMAIN-SUFFIX,hot.m.shouji.360tpcdn.com,AdBlock\n - DOMAIN-SUFFIX,hot-mob.com,AdBlock\n - DOMAIN-SUFFIX,hotrank.com.tw,AdBlock\n - DOMAIN-SUFFIX,houdaolj.com,AdBlock\n - DOMAIN-SUFFIX,houtai.2345.com,AdBlock\n - DOMAIN-SUFFIX,hpd.baidu.com,AdBlock\n - DOMAIN-SUFFIX,hpqxznpb.bid,AdBlock\n - DOMAIN-SUFFIX,hqgjcm.com,AdBlock\n - DOMAIN-SUFFIX,hr41.cn,AdBlock\n - DOMAIN-SUFFIX,hr44.com,AdBlock\n - DOMAIN-SUFFIX,hs.qhupdate.com,AdBlock\n - DOMAIN-SUFFIX,hslyqs.com,AdBlock\n - DOMAIN-SUFFIX,ht.www.sogou.com,AdBlock\n - DOMAIN-SUFFIX,htfmbt.com,AdBlock\n - DOMAIN-SUFFIX,htjsk.com,AdBlock\n - DOMAIN-SUFFIX,html.350.com,AdBlock\n - DOMAIN-SUFFIX,html.sunday8.com,AdBlock\n - DOMAIN-SUFFIX,html.yuntzs.com,AdBlock\n - DOMAIN-SUFFIX,httpdns.push.oppomobile.com,AdBlock\n - DOMAIN-SUFFIX,huahuaka.com,AdBlock\n - DOMAIN-SUFFIX,huashengtai.net,AdBlock\n - DOMAIN-SUFFIX,huashuowork.com,AdBlock\n - DOMAIN-SUFFIX,huaxinxunye.cn,AdBlock\n - DOMAIN-SUFFIX,huayi65.com,AdBlock\n - DOMAIN-SUFFIX,hub5pn.wap.sandai.net,AdBlock\n - DOMAIN-SUFFIX,hubojd.com,AdBlock\n - DOMAIN-SUFFIX,huichuan.sm.cn,AdBlock\n - DOMAIN-SUFFIX,huimee.net,AdBlock\n - DOMAIN-SUFFIX,huishenghuiying.com,AdBlock\n - DOMAIN-SUFFIX,huishenghuiying.com.cn,AdBlock\n - DOMAIN-SUFFIX,humanding.com,AdBlock\n - DOMAIN-SUFFIX,hunpingou.com,AdBlock\n - DOMAIN-SUFFIX,huodonghezi.com,AdBlock\n - DOMAIN-SUFFIX,huoying666.com,AdBlock\n - DOMAIN-SUFFIX,hv.code.tanwanyx.com,AdBlock\n - DOMAIN-SUFFIX,hw6.com,AdBlock\n - DOMAIN-SUFFIX,hwt.player888.cn,AdBlock\n - DOMAIN-SUFFIX,hxadt.com,AdBlock\n - DOMAIN-SUFFIX,hxspc.com,AdBlock\n - DOMAIN-SUFFIX,hxstfxx.cn,AdBlock\n - DOMAIN-SUFFIX,hxueu.code.weddingeeos.com,AdBlock\n - DOMAIN-SUFFIX,hxyifu.com,AdBlock\n - DOMAIN-SUFFIX,hxyx360.com,AdBlock\n - DOMAIN-SUFFIX,hyfh.benbaisteel.com,AdBlock\n - DOMAIN-SUFFIX,hyfyuan.com,AdBlock\n - DOMAIN-SUFFIX,hyperpromote.com,AdBlock\n - DOMAIN-SUFFIX,hypersnap.net,AdBlock\n - DOMAIN-SUFFIX,hys4.com,AdBlock\n - DOMAIN-SUFFIX,hystq.com,AdBlock\n - DOMAIN-SUFFIX,hytgj.com,AdBlock\n - DOMAIN-SUFFIX,hyz86.com,AdBlock\n - DOMAIN-SUFFIX,hz.miercn.com,AdBlock\n - DOMAIN-SUFFIX,hz.shouyoutv.com,AdBlock\n - DOMAIN-SUFFIX,hzaibi.com,AdBlock\n - DOMAIN-SUFFIX,hzdmacore.kejet.net,AdBlock\n - DOMAIN-SUFFIX,hzhyhm.com,AdBlock\n - DOMAIN-SUFFIX,hzsod71wov.me,AdBlock\n - DOMAIN-SUFFIX,hzxfmc.com,AdBlock\n - DOMAIN-SUFFIX,hzyuw.com,AdBlock\n - DOMAIN-SUFFIX,i.bigmir.net,AdBlock\n - DOMAIN-SUFFIX,i.clkservice.youdao.com,AdBlock\n - DOMAIN-SUFFIX,i.dreamfull.cn,AdBlock\n - DOMAIN-SUFFIX,i.flow.browser.oppomobile.com,AdBlock\n - DOMAIN-SUFFIX,i.go.sohu.com,AdBlock\n - DOMAIN-SUFFIX,i.haloapps.com,AdBlock\n - DOMAIN-SUFFIX,i.hao61.net,AdBlock\n - DOMAIN-SUFFIX,i.holalauncher.com,AdBlock\n - DOMAIN-SUFFIX,i.huilixieye.net,AdBlock\n - DOMAIN-SUFFIX,i.jiathis.com,AdBlock\n - DOMAIN-SUFFIX,i.jyhwt.cn,AdBlock\n - DOMAIN-SUFFIX,i.l.cnn.net,AdBlock\n - DOMAIN-SUFFIX,i.liadm.com,AdBlock\n - DOMAIN-SUFFIX,i.ma.social-touch.com,AdBlock\n - DOMAIN-SUFFIX,i.mmcdn.cn,AdBlock\n - DOMAIN-SUFFIX,i.ssix.io,AdBlock\n - DOMAIN-SUFFIX,i.syasn.com,AdBlock\n - DOMAIN-SUFFIX,i.tansuotv.com,AdBlock\n - DOMAIN-SUFFIX,i.w55c.net,AdBlock\n - DOMAIN-SUFFIX,i.zhuoyaju.com,AdBlock\n - DOMAIN-SUFFIX,i1236.net,AdBlock\n - DOMAIN-SUFFIX,i2.akjunshi.com,AdBlock\n - DOMAIN-SUFFIX,i3818.com,AdBlock\n - DOMAIN-SUFFIX,i5.akjunshi.com,AdBlock\n - DOMAIN-SUFFIX,i92xue.com,AdBlock\n - DOMAIN-SUFFIX,ia.ctags.cn,AdBlock\n - DOMAIN-SUFFIX,iad.g.163.com,AdBlock\n - DOMAIN-SUFFIX,iadc.qwapi.com,AdBlock\n - DOMAIN-SUFFIX,iadmatvideo.nosdn.127.net,AdBlock\n - DOMAIN-SUFFIX,iadmusicmat.music.126.net,AdBlock\n - DOMAIN-SUFFIX,iads.xinmin.cn,AdBlock\n - DOMAIN-SUFFIX,iadsdk.apple.com,AdBlock\n - DOMAIN-SUFFIX,ib.adnxs.co,AdBlock\n - DOMAIN-SUFFIX,ibafnw.cn,AdBlock\n - DOMAIN-SUFFIX,ibanners.empoweredcomms.com.au,AdBlock\n - DOMAIN-SUFFIX,ic.wps.cn,AdBlock\n - DOMAIN-SUFFIX,icast.cn,AdBlock\n - DOMAIN-SUFFIX,icdxc.com,AdBlock\n - DOMAIN-SUFFIX,ichaosheng.com,AdBlock\n - DOMAIN-SUFFIX,icn.southmoney.com,AdBlock\n - DOMAIN-SUFFIX,ico.58pic.com,AdBlock\n - DOMAIN-SUFFIX,icon.cnmo.com,AdBlock\n - DOMAIN-SUFFIX,icons.mydrivers.com,AdBlock\n - DOMAIN-SUFFIX,iconworkshop.cn,AdBlock\n - DOMAIN-SUFFIX,id.jiathis.com,AdBlock\n - DOMAIN-SUFFIX,id528.com,AdBlock\n - DOMAIN-SUFFIX,ida.cnool.net,AdBlock\n - DOMAIN-SUFFIX,idasai.com,AdBlock\n - DOMAIN-SUFFIX,idcot.com,AdBlock\n - DOMAIN-SUFFIX,idcqi.com,AdBlock\n - DOMAIN-SUFFIX,identified.cn,AdBlock\n - DOMAIN-SUFFIX,idianfang.com,AdBlock\n - DOMAIN-SUFFIX,idm-su.baidu.com,AdBlock\n - DOMAIN-SUFFIX,ids.deliver.ifeng.com,AdBlock\n - DOMAIN-SUFFIX,ids1.deliver.ifeng.com,AdBlock\n - DOMAIN-SUFFIX,idx.m.hub.sandai.net,AdBlock\n - DOMAIN-SUFFIX,ie8eamus.com,AdBlock\n - DOMAIN-SUFFIX,iebar.baidu.com,AdBlock\n - DOMAIN-SUFFIX,ieonline.microsoft.com,AdBlock\n - DOMAIN-SUFFIX,if1512.com,AdBlock\n - DOMAIN-SUFFIX,ifengad.3g.ifeng.com,AdBlock\n - DOMAIN-SUFFIX,iflyad.bj.openstorage.cn,AdBlock\n - DOMAIN-SUFFIX,iframe.travel.yahoo.com,AdBlock\n - DOMAIN-SUFFIX,ig.nukefans.net,AdBlock\n - DOMAIN-SUFFIX,igj5y.yongchanghengyuan.com,AdBlock\n - DOMAIN-SUFFIX,ih.adscale.de,AdBlock\n - DOMAIN-SUFFIX,ihualun.com,AdBlock\n - DOMAIN-SUFFIX,ihuanmei.com,AdBlock\n - DOMAIN-SUFFIX,iia1.pikacn.com,AdBlock\n - DOMAIN-SUFFIX,iiad.com,AdBlock\n - DOMAIN-SUFFIX,iiewl.com,AdBlock\n - DOMAIN-SUFFIX,iii.6park.com,AdBlock\n - DOMAIN-SUFFIX,iis1.deliver.ifeng.com,AdBlock\n - DOMAIN-SUFFIX,iis3g.deliver.ifeng.com,AdBlock\n - DOMAIN-SUFFIX,iisl7wpf.me,AdBlock\n - DOMAIN-SUFFIX,ikcode.baidu.com,AdBlock\n - DOMAIN-SUFFIX,il8r.com,AdBlock\n - DOMAIN-SUFFIX,im.jpush.cn,AdBlock\n - DOMAIN-SUFFIX,im.ov.yahoo.co.jp,AdBlock\n - DOMAIN-SUFFIX,im1.56zzw.com,AdBlock\n - DOMAIN-SUFFIX,im64.jpush.cn,AdBlock\n - DOMAIN-SUFFIX,ima3vpaid.appspot.com,AdBlock\n - DOMAIN-SUFFIX,imads.rediff.com,AdBlock\n - DOMAIN-SUFFIX,image.139y.com,AdBlock\n - DOMAIN-SUFFIX,image.9duw.com,AdBlock\n - DOMAIN-SUFFIX,image.box.xiaomi.com,AdBlock\n - DOMAIN-SUFFIX,image.fsyule.net,AdBlock\n - DOMAIN-SUFFIX,image.gentags.com,AdBlock\n - DOMAIN-SUFFIX,image.haiyunx.com,AdBlock\n - DOMAIN-SUFFIX,image.hh010.com,AdBlock\n - DOMAIN-SUFFIX,image.hj217.com,AdBlock\n - DOMAIN-SUFFIX,image.p4p.sogou.com,AdBlock\n - DOMAIN-SUFFIX,image.qj175.com,AdBlock\n - DOMAIN-SUFFIX,image.zzd.sm.cn,AdBlock\n - DOMAIN-SUFFIX,imagelx.yidianzixun.com,AdBlock\n - DOMAIN-SUFFIX,images.avsmt.cn,AdBlock\n - DOMAIN-SUFFIX,images.chinaz.com,AdBlock\n - DOMAIN-SUFFIX,images.enet.com.cn,AdBlock\n - DOMAIN-SUFFIX,images.fastclick.net,AdBlock\n - DOMAIN-SUFFIX,images.gxsky.com,AdBlock\n - DOMAIN-SUFFIX,images.intellitxt.com,AdBlock\n - DOMAIN-SUFFIX,images.millennialmedia.com,AdBlock\n - DOMAIN-SUFFIX,images.pagechoice.net,AdBlock\n - DOMAIN-SUFFIX,images.sohu.com,AdBlock\n - DOMAIN-SUFFIX,images.startappservice.com,AdBlock\n - DOMAIN-SUFFIX,images.tyyjzs.cn,AdBlock\n - DOMAIN-SUFFIX,images9999.com,AdBlock\n - DOMAIN-SUFFIX,imageter.com,AdBlock\n - DOMAIN-SUFFIX,imagzine.oppomobile.com,AdBlock\n - DOMAIN-SUFFIX,imedia.bokecc.com,AdBlock\n - DOMAIN-SUFFIX,imeijiajia.com,AdBlock\n - DOMAIN-SUFFIX,imfsr.lenovomm.com,AdBlock\n - DOMAIN-SUFFIX,img.12584.cn,AdBlock\n - DOMAIN-SUFFIX,img.3sjt.com,AdBlock\n - DOMAIN-SUFFIX,img.88ads.com,AdBlock\n - DOMAIN-SUFFIX,img.9duw.com,AdBlock\n - DOMAIN-SUFFIX,img.ad.zhangyue.com,AdBlock\n - DOMAIN-SUFFIX,img.adbox.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,img.adnyg.com,AdBlock\n - DOMAIN-SUFFIX,img.amp.ad.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,img.cmm.xmfish.com,AdBlock\n - DOMAIN-SUFFIX,img.cxxyft.com,AdBlock\n - DOMAIN-SUFFIX,img.dawenxue.org,AdBlock\n - DOMAIN-SUFFIX,img.dydab.com,AdBlock\n - DOMAIN-SUFFIX,img.ercfh.com,AdBlock\n - DOMAIN-SUFFIX,img.fd7c.com,AdBlock\n - DOMAIN-SUFFIX,img.feitian001.com,AdBlock\n - DOMAIN-SUFFIX,img.gaore.com,AdBlock\n - DOMAIN-SUFFIX,img.gz9d.com,AdBlock\n - DOMAIN-SUFFIX,img.il8r.com,AdBlock\n - DOMAIN-SUFFIX,img.img18.com,AdBlock\n - DOMAIN-SUFFIX,img.jgchq.com,AdBlock\n - DOMAIN-SUFFIX,img.jizzads.com,AdBlock\n - DOMAIN-SUFFIX,img.kanuxian.cn,AdBlock\n - DOMAIN-SUFFIX,img.khlxw.com,AdBlock\n - DOMAIN-SUFFIX,img.kuwanpx.com,AdBlock\n - DOMAIN-SUFFIX,img.libdd.com,AdBlock\n - DOMAIN-SUFFIX,img.ma.social-touch.com,AdBlock\n - DOMAIN-SUFFIX,img.meipic.net,AdBlock\n - DOMAIN-SUFFIX,img.qdscgj.com,AdBlock\n - DOMAIN-SUFFIX,img.qqgeshou.com,AdBlock\n - DOMAIN-SUFFIX,img.s8bbs.com,AdBlock\n - DOMAIN-SUFFIX,img.scupio.com,AdBlock\n - DOMAIN-SUFFIX,img.sheyuansu.com,AdBlock\n - DOMAIN-SUFFIX,img.supfast.net,AdBlock\n - DOMAIN-SUFFIX,img.tan5858.com,AdBlock\n - DOMAIN-SUFFIX,img.taotaosou.cn,AdBlock\n - DOMAIN-SUFFIX,img.tcdxt.com,AdBlock\n - DOMAIN-SUFFIX,img.toppr.com.cn,AdBlock\n - DOMAIN-SUFFIX,img.twcczhu.com,AdBlock\n - DOMAIN-SUFFIX,img.uyangyong.cn,AdBlock\n - DOMAIN-SUFFIX,img.wan.sogou.com,AdBlock\n - DOMAIN-SUFFIX,img.wuben56.com,AdBlock\n - DOMAIN-SUFFIX,img.xa9t.com,AdBlock\n - DOMAIN-SUFFIX,img.xcy8.com,AdBlock\n - DOMAIN-SUFFIX,img.xiacaidd.com,AdBlock\n - DOMAIN-SUFFIX,img.xuenb.com,AdBlock\n - DOMAIN-SUFFIX,img.yingshidiguo.cn,AdBlock\n - DOMAIN-SUFFIX,img.yuyue007.cn,AdBlock\n - DOMAIN-SUFFIX,img.zsj18.com,AdBlock\n - DOMAIN-SUFFIX,img.zuowen8.com,AdBlock\n - DOMAIN-SUFFIX,img.zx590.com,AdBlock\n - DOMAIN-SUFFIX,img0.egou.com,AdBlock\n - DOMAIN-SUFFIX,img01.taotaosou.cn,AdBlock\n - DOMAIN-SUFFIX,img1.126.net,AdBlock\n - DOMAIN-SUFFIX,img1.18183.com,AdBlock\n - DOMAIN-SUFFIX,img1.jintang114.org,AdBlock\n - DOMAIN-SUFFIX,img1.km.com,AdBlock\n - DOMAIN-SUFFIX,img1.mekbet.com,AdBlock\n - DOMAIN-SUFFIX,img1.nend.net,AdBlock\n - DOMAIN-SUFFIX,img1.pcfg.cache.wps.cn,AdBlock\n - DOMAIN-SUFFIX,img1.pszyzxh.org,AdBlock\n - DOMAIN-SUFFIX,img18.com,AdBlock\n - DOMAIN-SUFFIX,img2.126.net,AdBlock\n - DOMAIN-SUFFIX,img2.578965.com,AdBlock\n - DOMAIN-SUFFIX,img2.cs153.com,AdBlock\n - DOMAIN-SUFFIX,img2.hrccb.com,AdBlock\n - DOMAIN-SUFFIX,img2.jiuzhilan.com,AdBlock\n - DOMAIN-SUFFIX,img2.km.com,AdBlock\n - DOMAIN-SUFFIX,img2.qekun.com,AdBlock\n - DOMAIN-SUFFIX,img3.126.net,AdBlock\n - DOMAIN-SUFFIX,img3.fy1g.com,AdBlock\n - DOMAIN-SUFFIX,img3.km.com,AdBlock\n - DOMAIN-SUFFIX,img6.126.net,AdBlock\n - DOMAIN-SUFFIX,img80.net,AdBlock\n - DOMAIN-SUFFIX,img-ad.oupeng.com,AdBlock\n - DOMAIN-SUFFIX,imgad.thepaper.cn,AdBlock\n - DOMAIN-SUFFIX,imgad0.3conline.com,AdBlock\n - DOMAIN-SUFFIX,imgad0.pconline.com.cn,AdBlock\n - DOMAIN-SUFFIX,imgadpai.thepaper.cn,AdBlock\n - DOMAIN-SUFFIX,imgapp.yeyou.com,AdBlock\n - DOMAIN-SUFFIX,imgc.cymzc.com,AdBlock\n - DOMAIN-SUFFIX,imgcdn.wapx.cn,AdBlock\n - DOMAIN-SUFFIX,img-cdn-spot.ymcdn.cn,AdBlock\n - DOMAIN-SUFFIX,img-dsp.oss-cn-beijing.aliyuncs.com,AdBlock\n - DOMAIN-SUFFIX,imges.wu65.com,AdBlock\n - DOMAIN-SUFFIX,imgg.marketgid.com,AdBlock\n - DOMAIN-SUFFIX,imgg.mgid.com,AdBlock\n - DOMAIN-SUFFIX,imgp.cymzc.com,AdBlock\n - DOMAIN-SUFFIX,imgsreview.dftoutiao.com,AdBlock\n - DOMAIN-SUFFIX,imindmap.cc,AdBlock\n - DOMAIN-SUFFIX,immob.cn,AdBlock\n - DOMAIN-SUFFIX,imneinei.com,AdBlock\n - DOMAIN-SUFFIX,i-mobile.co.jp,AdBlock\n - DOMAIN-SUFFIX,imp.asahi.com,AdBlock\n - DOMAIN-SUFFIX,imp.gentags.net,AdBlock\n - DOMAIN-SUFFIX,imp.go.sohu.com,AdBlock\n - DOMAIN-SUFFIX,imp.madserving.com,AdBlock\n - DOMAIN-SUFFIX,imp.pdb.madserving.com,AdBlock\n - DOMAIN-SUFFIX,imp.xgo.com.cn,AdBlock\n - DOMAIN-SUFFIX,imp.zdnet.com.cn,AdBlock\n - DOMAIN-SUFFIX,imp.zol.com.cn,AdBlock\n - DOMAIN-SUFFIX,impression.gridsumdissector.com,AdBlock\n - DOMAIN-SUFFIX,impservice.dictapp.youdao.com,AdBlock\n - DOMAIN-SUFFIX,impservice.youdao.com,AdBlock\n - DOMAIN-SUFFIX,impservice2.youdao.com,AdBlock\n - DOMAIN-SUFFIX,impservicetest.dictapp.youdao.com,AdBlock\n - DOMAIN-SUFFIX,impservice-test.dictapp.youdao.com,AdBlock\n - DOMAIN-SUFFIX,imrworldwide.com,AdBlock\n - DOMAIN-SUFFIX,in.gyeet.com,AdBlock\n - DOMAIN-SUFFIX,in.jxhcyc.com,AdBlock\n - DOMAIN-SUFFIX,in.mengpr.com,AdBlock\n - DOMAIN-SUFFIX,in.mgwcn.com,AdBlock\n - DOMAIN-SUFFIX,in.qzkxt.com,AdBlock\n - DOMAIN-SUFFIX,in.zog.link,AdBlock\n - DOMAIN-SUFFIX,in1.feed.uu.cc,AdBlock\n - DOMAIN-SUFFIX,in1.secure.uu.cc,AdBlock\n - DOMAIN-SUFFIX,inad.com,AdBlock\n - DOMAIN-SUFFIX,inapp.1sapp.com,AdBlock\n - DOMAIN-SUFFIX,inccnd.com,AdBlock\n - DOMAIN-SUFFIX,inclk.com,AdBlock\n - DOMAIN-SUFFIX,include.xs2345.com,AdBlock\n - DOMAIN-SUFFIX,index.woai310.com,AdBlock\n - DOMAIN-SUFFIX,indieclick.3janecdn.com,AdBlock\n - DOMAIN-SUFFIX,info.downsave.com,AdBlock\n - DOMAIN-SUFFIX,info.gomlab.com,AdBlock\n - DOMAIN-SUFFIX,info.meihua.docer.com,AdBlock\n - DOMAIN-SUFFIX,info.pinyin.sogou.com,AdBlock\n - DOMAIN-SUFFIX,info.sec.miui.com,AdBlock\n - DOMAIN-SUFFIX,info.stockstar.com,AdBlock\n - DOMAIN-SUFFIX,info.yitsoftware.com,AdBlock\n - DOMAIN-SUFFIX,info4.video.qq.com,AdBlock\n - DOMAIN-SUFFIX,info6.video.qq.com,AdBlock\n - DOMAIN-SUFFIX,infocenter.meizu.com,AdBlock\n - DOMAIN-SUFFIX,ingameads.gameloft.com,AdBlock\n - DOMAIN-SUFFIX,ini.litingxin.cn,AdBlock\n - DOMAIN-SUFFIX,ini.update.360safe.com,AdBlock\n - DOMAIN-SUFFIX,init.phpwind.com,AdBlock\n - DOMAIN-SUFFIX,init.phpwind.net,AdBlock\n - DOMAIN-SUFFIX,init.startappexchange.com,AdBlock\n - DOMAIN-SUFFIX,innity.com,AdBlock\n - DOMAIN-SUFFIX,innity.net,AdBlock\n - DOMAIN-SUFFIX,inoprosport.su,AdBlock\n - DOMAIN-SUFFIX,insenz.com,AdBlock\n - DOMAIN-SUFFIX,inside.bitcomet.com,AdBlock\n - DOMAIN-SUFFIX,inskin.vo.llnwd.net,AdBlock\n - DOMAIN-SUFFIX,inst.360safe.com,AdBlock\n - DOMAIN-SUFFIX,instabug.com,AdBlock\n - DOMAIN-SUFFIX,install.kugou.com,AdBlock\n - DOMAIN-SUFFIX,install.sidesearch.lycos.com,AdBlock\n - DOMAIN-SUFFIX,install2.kugou.com,AdBlock\n - DOMAIN-SUFFIX,instreet.cn,AdBlock\n - DOMAIN-SUFFIX,int.dpool.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,inte.theta.sogoucdn.com,AdBlock\n - DOMAIN-SUFFIX,intellitxt.com,AdBlock\n - DOMAIN-SUFFIX,intely.cn,AdBlock\n - DOMAIN-SUFFIX,inter1ads.com,AdBlock\n - DOMAIN-SUFFIX,interaction.bayimob.com,AdBlock\n - DOMAIN-SUFFIX,interactive.huanqiu.com,AdBlock\n - DOMAIN-SUFFIX,interest.mix.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,ioc.mmakd.top,AdBlock\n - DOMAIN-SUFFIX,ios.bugly.qq.com,AdBlock\n - DOMAIN-SUFFIX,ios.video.mpush.qq.com,AdBlock\n - DOMAIN-SUFFIX,ios-dc.51y5.net,AdBlock\n - DOMAIN-SUFFIX,ios-informationplatform.wps.cn,AdBlock\n - DOMAIN-SUFFIX,iosipa.b0.upaiyun.com,AdBlock\n - DOMAIN-SUFFIX,ip.hivps.xyz,AdBlock\n - DOMAIN-SUFFIX,ip2.pxene.com,AdBlock\n - DOMAIN-SUFFIX,ipengtai.huanqiu.com,AdBlock\n - DOMAIN-SUFFIX,iperceptions.com,AdBlock\n - DOMAIN-SUFFIX,iphonelog.shouji.baofeng.com,AdBlock\n - DOMAIN-SUFFIX,ipic.staticsdo.com,AdBlock\n - DOMAIN-SUFFIX,ipinyou.com,AdBlock\n - DOMAIN-SUFFIX,ipm.atm.cp31.ott.cibntv.net,AdBlock\n - DOMAIN-SUFFIX,ipm.atm.youku.com,AdBlock\n - DOMAIN-SUFFIX,iqiyi.irs01.com,AdBlock\n - DOMAIN-SUFFIX,ir.mail.126.com,AdBlock\n - DOMAIN-SUFFIX,ir.mail.163.com,AdBlock\n - DOMAIN-SUFFIX,ir.mail.yeah.net,AdBlock\n - DOMAIN-SUFFIX,iroby.com,AdBlock\n - DOMAIN-SUFFIX,irpmt.mail.163.com,AdBlock\n - DOMAIN-SUFFIX,irs01.com,AdBlock\n - DOMAIN-SUFFIX,irs01.net,AdBlock\n - DOMAIN-SUFFIX,irs09.com,AdBlock\n - DOMAIN-SUFFIX,ishop789.com,AdBlock\n - DOMAIN-SUFFIX,ishowbg.com,AdBlock\n - DOMAIN-SUFFIX,istreamsche.com,AdBlock\n - DOMAIN-SUFFIX,itaoxiaoshuo.com,AdBlock\n - DOMAIN-SUFFIX,item.ttkvod.com,AdBlock\n - DOMAIN-SUFFIX,items.bingdiantao.com,AdBlock\n - DOMAIN-SUFFIX,its.fugetech.com,AdBlock\n - DOMAIN-SUFFIX,its-dori.tumblr.com,AdBlock\n - DOMAIN-SUFFIX,iutr.uozwys.top,AdBlock\n - DOMAIN-SUFFIX,iuuff.com,AdBlock\n - DOMAIN-SUFFIX,ivy.pcauto.com.cn,AdBlock\n - DOMAIN-SUFFIX,ivy.pcbaby.com.cn,AdBlock\n - DOMAIN-SUFFIX,ivy.pclady.com.cn,AdBlock\n - DOMAIN-SUFFIX,ivy.pconline.com.cn,AdBlock\n - DOMAIN-SUFFIX,iwan.sogou.com,AdBlock\n - DOMAIN-SUFFIX,iwanad.baidu.com,AdBlock\n - DOMAIN-SUFFIX,ixpub.net,AdBlock\n - DOMAIN-SUFFIX,j.6avz.com,AdBlock\n - DOMAIN-SUFFIX,j.baminw.cn,AdBlock\n - DOMAIN-SUFFIX,j.biquge520.cc,AdBlock\n - DOMAIN-SUFFIX,j.br.baidu.com,AdBlock\n - DOMAIN-SUFFIX,j.ccnovel.com,AdBlock\n - DOMAIN-SUFFIX,j.chaorenjiaoshi.com,AdBlock\n - DOMAIN-SUFFIX,j.dipowang.cn,AdBlock\n - DOMAIN-SUFFIX,j.fd7c.com,AdBlock\n - DOMAIN-SUFFIX,j.hbwcl.com,AdBlock\n - DOMAIN-SUFFIX,j.hongyangpai.com,AdBlock\n - DOMAIN-SUFFIX,j.jimeilm.com,AdBlock\n - DOMAIN-SUFFIX,j.kfd3sm2c.com,AdBlock\n - DOMAIN-SUFFIX,j.qijijs.top,AdBlock\n - DOMAIN-SUFFIX,j.qiqivv.com,AdBlock\n - DOMAIN-SUFFIX,j.qiqiww.com,AdBlock\n - DOMAIN-SUFFIX,j.s11.cn,AdBlock\n - DOMAIN-SUFFIX,j.sc1369.com,AdBlock\n - DOMAIN-SUFFIX,j.sdqoi2d.com,AdBlock\n - DOMAIN-SUFFIX,j.wan.liebao.cn,AdBlock\n - DOMAIN-SUFFIX,j.wit.qq.com,AdBlock\n - DOMAIN-SUFFIX,j.xinshipu.com,AdBlock\n - DOMAIN-SUFFIX,j.yljiaoluo.com,AdBlock\n - DOMAIN-SUFFIX,j.ytbt.cc,AdBlock\n - DOMAIN-SUFFIX,j.zhdap.com,AdBlock\n - DOMAIN-SUFFIX,j1.piaobing.com,AdBlock\n - DOMAIN-SUFFIX,j17.shangc.net,AdBlock\n - DOMAIN-SUFFIX,j17.xiumu.cn,AdBlock\n - DOMAIN-SUFFIX,j520s.gzcl999.cn,AdBlock\n - DOMAIN-SUFFIX,j7182.hfxcsl.cn,AdBlock\n - DOMAIN-SUFFIX,ja.gamersky.com,AdBlock\n - DOMAIN-SUFFIX,ja1.gamersky.com,AdBlock\n - DOMAIN-SUFFIX,ja9377.com,AdBlock\n - DOMAIN-SUFFIX,jack.okkkk.com,AdBlock\n - DOMAIN-SUFFIX,jackaow.com,AdBlock\n - DOMAIN-SUFFIX,jagcn.com,AdBlock\n - DOMAIN-SUFFIX,jav23.com,AdBlock\n - DOMAIN-SUFFIX,javhd.com,AdBlock\n - DOMAIN-SUFFIX,jb.4hw.com.cn,AdBlock\n - DOMAIN-SUFFIX,jb.asqql.com,AdBlock\n - DOMAIN-SUFFIX,jb.dianshu119.com,AdBlock\n - DOMAIN-SUFFIX,jb.eastlady.cn,AdBlock\n - DOMAIN-SUFFIX,jb.ecar168.cn,AdBlock\n - DOMAIN-SUFFIX,jb.mbaidu.top,AdBlock\n - DOMAIN-SUFFIX,jb.mnkan.com,AdBlock\n - DOMAIN-SUFFIX,jb.tupianzj.com,AdBlock\n - DOMAIN-SUFFIX,jbcbuy.com,AdBlock\n - DOMAIN-SUFFIX,jbflil.cn,AdBlock\n - DOMAIN-SUFFIX,jbyy010.com,AdBlock\n - DOMAIN-SUFFIX,jc.anhuilitian.net,AdBlock\n - DOMAIN-SUFFIX,jc.xuqinqi.cn,AdBlock\n - DOMAIN-SUFFIX,jc1.dayfund.cn,AdBlock\n - DOMAIN-SUFFIX,jct.maptu.cn,AdBlock\n - DOMAIN-SUFFIX,jczzjx.com,AdBlock\n - DOMAIN-SUFFIX,jd.c-ptsp.com.cn,AdBlock\n - DOMAIN-SUFFIX,jdb.jiudingcapital.cn,AdBlock\n - DOMAIN-SUFFIX,jdb.jiudingcapital.com,AdBlock\n - DOMAIN-SUFFIX,jddaw.com,AdBlock\n - DOMAIN-SUFFIX,jdg.bjygfd.com,AdBlock\n - DOMAIN-SUFFIX,jdkic.com,AdBlock\n - DOMAIN-SUFFIX,jdlcg.cn,AdBlock\n - DOMAIN-SUFFIX,jdlhg.com,AdBlock\n - DOMAIN-SUFFIX,jdw.zjuwjdc.com,AdBlock\n - DOMAIN-SUFFIX,jebe.renren.com,AdBlock\n - DOMAIN-SUFFIX,jebe.xnimg.cn,AdBlock\n - DOMAIN-SUFFIX,jellyfish.pandora.xiaomi.com,AdBlock\n - DOMAIN-SUFFIX,jermr.com,AdBlock\n - DOMAIN-SUFFIX,jesgoo.com,AdBlock\n - DOMAIN-SUFFIX,jf.winads.cn,AdBlock\n - DOMAIN-SUFFIX,jfhe.0769371.com,AdBlock\n - DOMAIN-SUFFIX,jfm4.pop.baofeng.net,AdBlock\n - DOMAIN-SUFFIX,jfqkj.com,AdBlock\n - DOMAIN-SUFFIX,jgchq.com,AdBlock\n - DOMAIN-SUFFIX,jghcy.com,AdBlock\n - DOMAIN-SUFFIX,jhakie.com,AdBlock\n - DOMAIN-SUFFIX,jhtcdj.com,AdBlock\n - DOMAIN-SUFFIX,jhzl001.com,AdBlock\n - DOMAIN-SUFFIX,ji.dazhantai.com,AdBlock\n - DOMAIN-SUFFIX,jiaheyonggu.com,AdBlock\n - DOMAIN-SUFFIX,jiajv.net,AdBlock\n - DOMAIN-SUFFIX,jianbaimei.com,AdBlock\n - DOMAIN-SUFFIX,jianduankm.com,AdBlock\n - DOMAIN-SUFFIX,jianmei123.com,AdBlock\n - DOMAIN-SUFFIX,jiansuo.dsxdn.com,AdBlock\n - DOMAIN-SUFFIX,jiaoben.eastday.com,AdBlock\n - DOMAIN-SUFFIX,jiaoben.ganji.cn,AdBlock\n - DOMAIN-SUFFIX,jiaoben.jucanw.com,AdBlock\n - DOMAIN-SUFFIX,jiaoben.junmeng.com,AdBlock\n - DOMAIN-SUFFIX,jiaoben.xinshipu.cn,AdBlock\n - DOMAIN-SUFFIX,jias.haotxt.com,AdBlock\n - DOMAIN-SUFFIX,jiathis.com,AdBlock\n - DOMAIN-SUFFIX,jiawen88.com,AdBlock\n - DOMAIN-SUFFIX,jiayi1.oss-cn-shanghai.aliyuncs.com,AdBlock\n - DOMAIN-SUFFIX,jiedaibao.com,AdBlock\n - DOMAIN-SUFFIX,jiehantai.com,AdBlock\n - DOMAIN-SUFFIX,jiehunmishu.com,AdBlock\n - DOMAIN-SUFFIX,jifeidandar.com,AdBlock\n - DOMAIN-SUFFIX,jifen.2345.com,AdBlock\n - DOMAIN-SUFFIX,jihehuaban.com,AdBlock\n - DOMAIN-SUFFIX,jihehuaban.com.cn,AdBlock\n - DOMAIN-SUFFIX,jimdo.com,AdBlock\n - DOMAIN-SUFFIX,jimeilm.com,AdBlock\n - DOMAIN-SUFFIX,jindu179.com,AdBlock\n - DOMAIN-SUFFIX,jing.58.com,AdBlock\n - DOMAIN-SUFFIX,jingdian230.meilika.net,AdBlock\n - DOMAIN-SUFFIX,jinghuazhijia.com,AdBlock\n - DOMAIN-SUFFIX,jinsha11833.com,AdBlock\n - DOMAIN-SUFFIX,jinshagt222.com,AdBlock\n - DOMAIN-SUFFIX,jira.vpon.com,AdBlock\n - DOMAIN-SUFFIX,jisucn.com,AdBlock\n - DOMAIN-SUFFIX,jiu.njdkgm.com,AdBlock\n - DOMAIN-SUFFIX,jiubuhua.com,AdBlock\n - DOMAIN-SUFFIX,jiuku.cc,AdBlock\n - DOMAIN-SUFFIX,jiyou2014.com,AdBlock\n - DOMAIN-SUFFIX,jizzads.com,AdBlock\n - DOMAIN-SUFFIX,jj123.com.cn,AdBlock\n - DOMAIN-SUFFIX,jjhd47.115seo.com,AdBlock\n - DOMAIN-SUFFIX,jjx.xjtxcj.com,AdBlock\n - DOMAIN-SUFFIX,jjxgly.com,AdBlock\n - DOMAIN-SUFFIX,jjyy.gaopengqcdz.cn,AdBlock\n - DOMAIN-SUFFIX,jk939.com,AdBlock\n - DOMAIN-SUFFIX,jkjjkj.top,AdBlock\n - DOMAIN-SUFFIX,jkmxy.com,AdBlock\n - DOMAIN-SUFFIX,jl027.com,AdBlock\n - DOMAIN-SUFFIX,jlssbz.com,AdBlock\n - DOMAIN-SUFFIX,jmonitor.jiuzhilan.com,AdBlock\n - DOMAIN-SUFFIX,jmsyzj.com,AdBlock\n - DOMAIN-SUFFIX,jmxlaser.com,AdBlock\n - DOMAIN-SUFFIX,jndczg.com,AdBlock\n - DOMAIN-SUFFIX,jnrsjm.com,AdBlock\n - DOMAIN-SUFFIX,jnsdkjzs.com,AdBlock\n - DOMAIN-SUFFIX,jnsz.net.cn,AdBlock\n - DOMAIN-SUFFIX,jnyngg.cn,AdBlock\n - DOMAIN-SUFFIX,johtzj.com,AdBlock\n - DOMAIN-SUFFIX,jointreport-switch.com,AdBlock\n - DOMAIN-SUFFIX,jossuer.net,AdBlock\n - DOMAIN-SUFFIX,joyfuldoors.com,AdBlock\n - DOMAIN-SUFFIX,jp88.cc,AdBlock\n - DOMAIN-SUFFIX,jpg.cooguo.com,AdBlock\n - DOMAIN-SUFFIX,jpg.inte.sogoucdn.com,AdBlock\n - DOMAIN-SUFFIX,jph.itiexue.net,AdBlock\n - DOMAIN-SUFFIX,jpush.cn,AdBlock\n - DOMAIN-SUFFIX,jpush.html5.qq.com,AdBlock\n - DOMAIN-SUFFIX,jqmt.qq.com,AdBlock\n - DOMAIN-SUFFIX,jqz9.com,AdBlock\n - DOMAIN-SUFFIX,jrdkc.com,AdBlock\n - DOMAIN-SUFFIX,jrhaigou.com,AdBlock\n - DOMAIN-SUFFIX,jrpt.jrptweb.org,AdBlock\n - DOMAIN-SUFFIX,js.05sun.com,AdBlock\n - DOMAIN-SUFFIX,js.133u.com,AdBlock\n - DOMAIN-SUFFIX,js.139y.com,AdBlock\n - DOMAIN-SUFFIX,js.1688988.com,AdBlock\n - DOMAIN-SUFFIX,js.2011.8684.com,AdBlock\n - DOMAIN-SUFFIX,js.45bubu.com,AdBlock\n - DOMAIN-SUFFIX,js.4hw.com.cn,AdBlock\n - DOMAIN-SUFFIX,js.5068.com,AdBlock\n - DOMAIN-SUFFIX,js.51taifu.com,AdBlock\n - DOMAIN-SUFFIX,js.578965.com,AdBlock\n - DOMAIN-SUFFIX,js.5iydz.com,AdBlock\n - DOMAIN-SUFFIX,js.9669.cn,AdBlock\n - DOMAIN-SUFFIX,js.adxkj.com,AdBlock\n - DOMAIN-SUFFIX,js.bju888.com,AdBlock\n - DOMAIN-SUFFIX,js.bxwns.com,AdBlock\n - DOMAIN-SUFFIX,js.bxwxtxt.com,AdBlock\n - DOMAIN-SUFFIX,js.cdjqjy.com,AdBlock\n - DOMAIN-SUFFIX,js.cncrk.com,AdBlock\n - DOMAIN-SUFFIX,js.cnmo.com,AdBlock\n - DOMAIN-SUFFIX,js.cnscdj.com,AdBlock\n - DOMAIN-SUFFIX,js.ctags.cn,AdBlock\n - DOMAIN-SUFFIX,js.daxueshengqiandai.com,AdBlock\n - DOMAIN-SUFFIX,js.dkqapp.cn,AdBlock\n - DOMAIN-SUFFIX,js.duotegame.com,AdBlock\n - DOMAIN-SUFFIX,js.ea3w.com,AdBlock\n - DOMAIN-SUFFIX,js.feitian001.com,AdBlock\n - DOMAIN-SUFFIX,js.fengniao.com,AdBlock\n - DOMAIN-SUFFIX,js.firefang.cn,AdBlock\n - DOMAIN-SUFFIX,js.gewuwen.com,AdBlock\n - DOMAIN-SUFFIX,js.hkslg520.com,AdBlock\n - DOMAIN-SUFFIX,js.hslyqs.com,AdBlock\n - DOMAIN-SUFFIX,js.icast.cn,AdBlock\n - DOMAIN-SUFFIX,js.idgdmg.com.cn,AdBlock\n - DOMAIN-SUFFIX,js.jianbaimei.com,AdBlock\n - DOMAIN-SUFFIX,js.jxabp.com.cn,AdBlock\n - DOMAIN-SUFFIX,js.lieqitianxia.cn,AdBlock\n - DOMAIN-SUFFIX,js.mbaidu.top,AdBlock\n - DOMAIN-SUFFIX,js.mingxianshanghang.cn,AdBlock\n - DOMAIN-SUFFIX,js.mnkan.com,AdBlock\n - DOMAIN-SUFFIX,js.moatads.com,AdBlock\n - DOMAIN-SUFFIX,js.mumayi.net,AdBlock\n - DOMAIN-SUFFIX,js.paochala.net,AdBlock\n - DOMAIN-SUFFIX,js.ptmind.com,AdBlock\n - DOMAIN-SUFFIX,js.pub.tom.com,AdBlock\n - DOMAIN-SUFFIX,js.pyangzi.com,AdBlock\n - DOMAIN-SUFFIX,js.revsci.net,AdBlock\n - DOMAIN-SUFFIX,js.ruiwen.com,AdBlock\n - DOMAIN-SUFFIX,js.saiqizhi.com,AdBlock\n - DOMAIN-SUFFIX,js.sanwen.net,AdBlock\n - DOMAIN-SUFFIX,js.soduso.cc,AdBlock\n - DOMAIN-SUFFIX,js.soonyou123.com,AdBlock\n - DOMAIN-SUFFIX,js.start1999.com,AdBlock\n - DOMAIN-SUFFIX,js.szande.com.cn,AdBlock\n - DOMAIN-SUFFIX,js.ubaike.cn,AdBlock\n - DOMAIN-SUFFIX,js.um0592.com,AdBlock\n - DOMAIN-SUFFIX,js.union-wifi.com,AdBlock\n - DOMAIN-SUFFIX,js.wo-x.cn,AdBlock\n - DOMAIN-SUFFIX,js.wu65.com,AdBlock\n - DOMAIN-SUFFIX,js.xiansuper.com,AdBlock\n - DOMAIN-SUFFIX,js.xtgreat.com,AdBlock\n - DOMAIN-SUFFIX,js.xuexila.com,AdBlock\n - DOMAIN-SUFFIX,js.ydeprint.com,AdBlock\n - DOMAIN-SUFFIX,js.yixui.com,AdBlock\n - DOMAIN-SUFFIX,js.ylunion.com,AdBlock\n - DOMAIN-SUFFIX,js.yoyi.tv,AdBlock\n - DOMAIN-SUFFIX,js.zol.com.cn,AdBlock\n - DOMAIN-SUFFIX,js.zyrfanli.com,AdBlock\n - DOMAIN-SUFFIX,js1.2abc8.com,AdBlock\n - DOMAIN-SUFFIX,js1.nend.net,AdBlock\n - DOMAIN-SUFFIX,js-1.pchome.net,AdBlock\n - DOMAIN-SUFFIX,js1.xbaixing.com,AdBlock\n - DOMAIN-SUFFIX,js1.zuocai.tv,AdBlock\n - DOMAIN-SUFFIX,js1151.yongkang6.com,AdBlock\n - DOMAIN-SUFFIX,js1151.zhudiaosz.com,AdBlock\n - DOMAIN-SUFFIX,js1157.yongkang6.com,AdBlock\n - DOMAIN-SUFFIX,js123.0937jyg.com,AdBlock\n - DOMAIN-SUFFIX,js1516.0937jyg.com,AdBlock\n - DOMAIN-SUFFIX,js1517.0937jyg.com,AdBlock\n - DOMAIN-SUFFIX,js205.dupinpu.com,AdBlock\n - DOMAIN-SUFFIX,js2254.hfxcsl.cn,AdBlock\n - DOMAIN-SUFFIX,js2553.xjzyq.com,AdBlock\n - DOMAIN-SUFFIX,js257.0937jyg.com,AdBlock\n - DOMAIN-SUFFIX,js2672.xjzyq.com,AdBlock\n - DOMAIN-SUFFIX,js3492.yongkang6.com,AdBlock\n - DOMAIN-SUFFIX,js3743.yongkang6.com,AdBlock\n - DOMAIN-SUFFIX,js3768.zhudiaosz.com,AdBlock\n - DOMAIN-SUFFIX,js3810.yongkang6.com,AdBlock\n - DOMAIN-SUFFIX,js3810.zhudiaosz.com,AdBlock\n - DOMAIN-SUFFIX,js4.eastmoney.com,AdBlock\n - DOMAIN-SUFFIX,js412.0937jyg.com,AdBlock\n - DOMAIN-SUFFIX,js412.yexfes.com,AdBlock\n - DOMAIN-SUFFIX,js412.yqjxzw.com,AdBlock\n - DOMAIN-SUFFIX,js4163.yongkang6.com,AdBlock\n - DOMAIN-SUFFIX,js4273.zhudiaosz.com,AdBlock\n - DOMAIN-SUFFIX,js453.zhudiaosz.com,AdBlock\n - DOMAIN-SUFFIX,js50.yxlady.com,AdBlock\n - DOMAIN-SUFFIX,js5162.yongkang6.com,AdBlock\n - DOMAIN-SUFFIX,js6882.jianbangjiaoyu.com,AdBlock\n - DOMAIN-SUFFIX,js6882.mengchengbao.com,AdBlock\n - DOMAIN-SUFFIX,js7004.hnfpgm.com,AdBlock\n - DOMAIN-SUFFIX,js7129.dlkjgjmy.com,AdBlock\n - DOMAIN-SUFFIX,js7129.shxqeps.com,AdBlock\n - DOMAIN-SUFFIX,js7152.shxqeps.com,AdBlock\n - DOMAIN-SUFFIX,js74.0937jyg.com,AdBlock\n - DOMAIN-SUFFIX,js74.yexfes.com,AdBlock\n - DOMAIN-SUFFIX,js74.yqjxzw.com,AdBlock\n - DOMAIN-SUFFIX,js7405.mengchengbao.com,AdBlock\n - DOMAIN-SUFFIX,js84.enyayinxiang.com,AdBlock\n - DOMAIN-SUFFIX,js883.hnfpgm.com,AdBlock\n - DOMAIN-SUFFIX,js883.yongkang6.com,AdBlock\n - DOMAIN-SUFFIX,js9318.bllzgqbyp.com,AdBlock\n - DOMAIN-SUFFIX,jsadt.com,AdBlock\n - DOMAIN-SUFFIX,js-agent.newrelic.com,AdBlock\n - DOMAIN-SUFFIX,js-apac-ss.ysm.yahoo.com,AdBlock\n - DOMAIN-SUFFIX,jsb.qianzhan.com,AdBlock\n - DOMAIN-SUFFIX,jsc.adskeeper.co.uk,AdBlock\n - DOMAIN-SUFFIX,jsc.marketgid.com,AdBlock\n - DOMAIN-SUFFIX,jsc.mgid.com,AdBlock\n - DOMAIN-SUFFIX,jscdn.99pps.com,AdBlock\n - DOMAIN-SUFFIX,jscode.jbzj.com,AdBlock\n - DOMAIN-SUFFIX,jsjs.nthyn.com,AdBlock\n - DOMAIN-SUFFIX,jskrnekewe.mofans.net,AdBlock\n - DOMAIN-SUFFIX,jsm.39yst.com,AdBlock\n - DOMAIN-SUFFIX,jsm.9939.com,AdBlock\n - DOMAIN-SUFFIX,jsmwd.com,AdBlock\n - DOMAIN-SUFFIX,jsnp.golden1.sogou.com,AdBlock\n - DOMAIN-SUFFIX,jsnywl.kfi8.com,AdBlock\n - DOMAIN-SUFFIX,json.gewuwen.com,AdBlock\n - DOMAIN-SUFFIX,jspg.cc,AdBlock\n - DOMAIN-SUFFIX,jsqmt.qq.com,AdBlock\n - DOMAIN-SUFFIX,jssd.uumeitu.com,AdBlock\n - DOMAIN-SUFFIX,jt.yunxiufang.net,AdBlock\n - DOMAIN-SUFFIX,jtug.code.poyang.com,AdBlock\n - DOMAIN-SUFFIX,jtxh.net,AdBlock\n - DOMAIN-SUFFIX,jtys8.com,AdBlock\n - DOMAIN-SUFFIX,ju33.com,AdBlock\n - DOMAIN-SUFFIX,juicyads.com,AdBlock\n - DOMAIN-SUFFIX,jump.luna.58.com,AdBlock\n - DOMAIN-SUFFIX,jumpe.58xmgys.com,AdBlock\n - DOMAIN-SUFFIX,jumpluna.58.com,AdBlock\n - DOMAIN-SUFFIX,jumpm.58xmgys.com,AdBlock\n - DOMAIN-SUFFIX,jundazulin.com,AdBlock\n - DOMAIN-SUFFIX,junfull.com,AdBlock\n - DOMAIN-SUFFIX,juren0.com,AdBlock\n - DOMAIN-SUFFIX,jusha.com,AdBlock\n - DOMAIN-SUFFIX,jutou5.com,AdBlock\n - DOMAIN-SUFFIX,juzi.cn,AdBlock\n - DOMAIN-SUFFIX,juzilm.com,AdBlock\n - DOMAIN-SUFFIX,jwg365.cn,AdBlock\n - DOMAIN-SUFFIX,jwpltx.com,AdBlock\n - DOMAIN-SUFFIX,jwqj.net,AdBlock\n - DOMAIN-SUFFIX,jwz.3conline.com,AdBlock\n - DOMAIN-SUFFIX,jx5m.com,AdBlock\n - DOMAIN-SUFFIX,jxad.jx163.com,AdBlock\n - DOMAIN-SUFFIX,jxbjt.com,AdBlock\n - DOMAIN-SUFFIX,jxfxsw.com,AdBlock\n - DOMAIN-SUFFIX,jxjzny.com,AdBlock\n - DOMAIN-SUFFIX,jxlog.istreamsche.com,AdBlock\n - DOMAIN-SUFFIX,jxlqgs.com,AdBlock\n - DOMAIN-SUFFIX,jxxiangchu.com,AdBlock\n - DOMAIN-SUFFIX,jyc.njxczy.com,AdBlock\n - DOMAIN-SUFFIX,jyd.fjzdmy.com,AdBlock\n - DOMAIN-SUFFIX,jystea.com,AdBlock\n - DOMAIN-SUFFIX,jyz.fjtzjy.com,AdBlock\n - DOMAIN-SUFFIX,jzkapp.com,AdBlock\n - DOMAIN-SUFFIX,jzm81.com,AdBlock\n - DOMAIN-SUFFIX,k.85wa.cn,AdBlock\n - DOMAIN-SUFFIX,k.ctsywy.com,AdBlock\n - DOMAIN-SUFFIX,k1w5.me,AdBlock\n - DOMAIN-SUFFIX,k2team.kyiv.ua,AdBlock\n - DOMAIN-SUFFIX,k3bos.com,AdBlock\n - DOMAIN-SUFFIX,kafka8.com,AdBlock\n - DOMAIN-SUFFIX,kaitongyewu.com,AdBlock\n - DOMAIN-SUFFIX,karma.mdpcdn.com,AdBlock\n - DOMAIN-SUFFIX,kas.keydot.net,AdBlock\n - DOMAIN-SUFFIX,kawa11.space,AdBlock\n - DOMAIN-SUFFIX,kbnetworkz.s3.amazonaws.com,AdBlock\n - DOMAIN-SUFFIX,kddtri.cn,AdBlock\n - DOMAIN-SUFFIX,kejet.com,AdBlock\n - DOMAIN-SUFFIX,kejet.net,AdBlock\n - DOMAIN-SUFFIX,kele4.com,AdBlock\n - DOMAIN-SUFFIX,ker.pic2pic.site,AdBlock\n - DOMAIN-SUFFIX,kermit.macnn.com,AdBlock\n - DOMAIN-SUFFIX,keryt.jnservo.com,AdBlock\n - DOMAIN-SUFFIX,ketchapp.org,AdBlock\n - DOMAIN-SUFFIX,keydot.net,AdBlock\n - DOMAIN-SUFFIX,keyrun.cn,AdBlock\n - DOMAIN-SUFFIX,keyrun.com,AdBlock\n - DOMAIN-SUFFIX,keyshot.cc,AdBlock\n - DOMAIN-SUFFIX,keystone.mwbsys.com,AdBlock\n - DOMAIN-SUFFIX,keyyou.net,AdBlock\n - DOMAIN-SUFFIX,kfewaz.zh1155.com,AdBlock\n - DOMAIN-SUFFIX,kfhuihe.net,AdBlock\n - DOMAIN-SUFFIX,kfluoa.com,AdBlock\n - DOMAIN-SUFFIX,kgcjgsa8.net,AdBlock\n - DOMAIN-SUFFIX,kgmobilestat.kugou.com,AdBlock\n - DOMAIN-SUFFIX,kguke.com,AdBlock\n - DOMAIN-SUFFIX,kho3au7l4z.me,AdBlock\n - DOMAIN-SUFFIX,kicnse.com,AdBlock\n - DOMAIN-SUFFIX,kingdeecn.cn,AdBlock\n - DOMAIN-SUFFIX,kingwam.com,AdBlock\n - DOMAIN-SUFFIX,kio.quanliyouxi.cn,AdBlock\n - DOMAIN-SUFFIX,kiss.blockplus.cc,AdBlock\n - DOMAIN-SUFFIX,kjgen.com,AdBlock\n - DOMAIN-SUFFIX,kk7kk.com,AdBlock\n - DOMAIN-SUFFIX,kkcaicai.com,AdBlock\n - DOMAIN-SUFFIX,kkpgv.kankan.com,AdBlock\n - DOMAIN-SUFFIX,kkpgv2.kankan.com,AdBlock\n - DOMAIN-SUFFIX,kld666.com,AdBlock\n - DOMAIN-SUFFIX,kldmm.com,AdBlock\n - DOMAIN-SUFFIX,klsdmr.com,AdBlock\n - DOMAIN-SUFFIX,kl-toys.com,AdBlock\n - DOMAIN-SUFFIX,klz28.com,AdBlock\n - DOMAIN-SUFFIX,km.jianduankm.com,AdBlock\n - DOMAIN-SUFFIX,kmadou.com,AdBlock\n - DOMAIN-SUFFIX,kmd365.com,AdBlock\n - DOMAIN-SUFFIX,kmwqxqh.com,AdBlock\n - DOMAIN-SUFFIX,kn.aishake.cn,AdBlock\n - DOMAIN-SUFFIX,kn.archrug.com,AdBlock\n - DOMAIN-SUFFIX,kn.barnfps.com,AdBlock\n - DOMAIN-SUFFIX,kn.bjbrtc.com,AdBlock\n - DOMAIN-SUFFIX,kn.chapnap.com,AdBlock\n - DOMAIN-SUFFIX,kn.chgdf.cn,AdBlock\n - DOMAIN-SUFFIX,kn.czzdf.com,AdBlock\n - DOMAIN-SUFFIX,kn.dyscsm.cn,AdBlock\n - DOMAIN-SUFFIX,kn.gzcce.cn,AdBlock\n - DOMAIN-SUFFIX,kn.jzhrty.cn,AdBlock\n - DOMAIN-SUFFIX,kn.nykps.com,AdBlock\n - DOMAIN-SUFFIX,kn.qhdfxkj.com,AdBlock\n - DOMAIN-SUFFIX,kn.qqqmdq.com,AdBlock\n - DOMAIN-SUFFIX,kn.qzdaren.com,AdBlock\n - DOMAIN-SUFFIX,kn.ynmhg.cn,AdBlock\n - DOMAIN-SUFFIX,kn.zstjy.com,AdBlock\n - DOMAIN-SUFFIX,kn.zzdahan.com,AdBlock\n - DOMAIN-SUFFIX,knet.cn,AdBlock\n - DOMAIN-SUFFIX,knnwdyou.com,AdBlock\n - DOMAIN-SUFFIX,kob.adxkj.com,AdBlock\n - DOMAIN-SUFFIX,kochava.com,AdBlock\n - DOMAIN-SUFFIX,kod4pc293.com,AdBlock\n - DOMAIN-SUFFIX,koowo.com,AdBlock\n - DOMAIN-SUFFIX,koukou7.com,AdBlock\n - DOMAIN-SUFFIX,kovjo.com,AdBlock\n - DOMAIN-SUFFIX,kqy1.com,AdBlock\n - DOMAIN-SUFFIX,kr.sybspools.com,AdBlock\n - DOMAIN-SUFFIX,krux.net,AdBlock\n - DOMAIN-SUFFIX,ksdsuzhou.com,AdBlock\n - DOMAIN-SUFFIX,ksr.juuhe.com,AdBlock\n - DOMAIN-SUFFIX,ksrsy.com,AdBlock\n - DOMAIN-SUFFIX,kstj.baidu.com,AdBlock\n - DOMAIN-SUFFIX,kt220.com,AdBlock\n - DOMAIN-SUFFIX,ktivn.uranus.sogou.com,AdBlock\n - DOMAIN-SUFFIX,ktunions.com,AdBlock\n - DOMAIN-SUFFIX,ktv0311.com,AdBlock\n - DOMAIN-SUFFIX,ku63.com,AdBlock\n - DOMAIN-SUFFIX,ku9377.com,AdBlock\n - DOMAIN-SUFFIX,kuaigao.rrsdl.com,AdBlock\n - DOMAIN-SUFFIX,kuaikaiapp.com,AdBlock\n - DOMAIN-SUFFIX,kuaikan.netmon.360safe.com,AdBlock\n - DOMAIN-SUFFIX,kuaipai666.cn,AdBlock\n - DOMAIN-SUFFIX,kuaizip.com,AdBlock\n - DOMAIN-SUFFIX,kualianyingxiao.cn,AdBlock\n - DOMAIN-SUFFIX,kudifish.com,AdBlock\n - DOMAIN-SUFFIX,kuguopush.com,AdBlock\n - DOMAIN-SUFFIX,kumihua.com,AdBlock\n - DOMAIN-SUFFIX,kuwoyy.com,AdBlock\n - DOMAIN-SUFFIX,kuyic.m.gxwztv.com,AdBlock\n - DOMAIN-SUFFIX,kuzai.cooguo.com,AdBlock\n - DOMAIN-SUFFIX,kw.ra.icast.cn,AdBlock\n - DOMAIN-SUFFIX,kwmsg.kuwo.cn,AdBlock\n - DOMAIN-SUFFIX,kwurl.ucweb.com,AdBlock\n - DOMAIN-SUFFIX,kxlogo.knet.cn,AdBlock\n - DOMAIN-SUFFIX,kxmav2.com,AdBlock\n - DOMAIN-SUFFIX,kxrxh.com,AdBlock\n - DOMAIN-SUFFIX,kyad88.com,AdBlock\n - DOMAIN-SUFFIX,kyzhecmvpiaw.com,AdBlock\n - DOMAIN-SUFFIX,l.adiers.com,AdBlock\n - DOMAIN-SUFFIX,l.betrad.com,AdBlock\n - DOMAIN-SUFFIX,l.minisplat.cn,AdBlock\n - DOMAIN-SUFFIX,l.mnjkw.cn,AdBlock\n - DOMAIN-SUFFIX,l.supfast.net,AdBlock\n - DOMAIN-SUFFIX,l.ujian.cc,AdBlock\n - DOMAIN-SUFFIX,l.yidianzixun.com,AdBlock\n - DOMAIN-SUFFIX,l1.soarfi.cn,AdBlock\n - DOMAIN-SUFFIX,l2.soarfi.cn,AdBlock\n - DOMAIN-SUFFIX,l9bdhcgihw.neihanw.com,AdBlock\n - DOMAIN-SUFFIX,labs.ra.icast.cn,AdBlock\n - DOMAIN-SUFFIX,laigame7.com,AdBlock\n - DOMAIN-SUFFIX,laiququan.com,AdBlock\n - DOMAIN-SUFFIX,lajizhan.org,AdBlock\n - DOMAIN-SUFFIX,lan.btwan5.com,AdBlock\n - DOMAIN-SUFFIX,langchars.com,AdBlock\n - DOMAIN-SUFFIX,langjiyisheng.com,AdBlock\n - DOMAIN-SUFFIX,lansha.tv,AdBlock\n - DOMAIN-SUFFIX,lanxiangji.com,AdBlock\n - DOMAIN-SUFFIX,laomaotao.net,AdBlock\n - DOMAIN-SUFFIX,laoqu123.com,AdBlock\n - DOMAIN-SUFFIX,lashou1000.com,AdBlock\n - DOMAIN-SUFFIX,lb.gtimg.com,AdBlock\n - DOMAIN-SUFFIX,lb.statsevent.com,AdBlock\n - DOMAIN-SUFFIX,lbstatic-a.akamaihd.net,AdBlock\n - DOMAIN-SUFFIX,lbszb.tongbu.com,AdBlock\n - DOMAIN-SUFFIX,lc.jiathis.com,AdBlock\n - DOMAIN-SUFFIX,lcs.dev.surepush.cn,AdBlock\n - DOMAIN-SUFFIX,ld.mediaget.com,AdBlock\n - DOMAIN-SUFFIX,ldpgl.code.mytanwan.com,AdBlock\n - DOMAIN-SUFFIX,lds.lenovomm.com,AdBlock\n - DOMAIN-SUFFIX,lds.zui.com,AdBlock\n - DOMAIN-SUFFIX,ldy.350.com,AdBlock\n - DOMAIN-SUFFIX,ldy.adqku.cn,AdBlock\n - DOMAIN-SUFFIX,le4le.com,AdBlock\n - DOMAIN-SUFFIX,leadbolt.net,AdBlock\n - DOMAIN-SUFFIX,leadboltads.net,AdBlock\n - DOMAIN-SUFFIX,leadboltapps.net,AdBlock\n - DOMAIN-SUFFIX,leadboltmobile.net,AdBlock\n - DOMAIN-SUFFIX,ledou.dl.uu.cc,AdBlock\n - DOMAIN-SUFFIX,leeyuoxs.com,AdBlock\n - DOMAIN-SUFFIX,legozu.com,AdBlock\n - DOMAIN-SUFFIX,lele999.com,AdBlock\n - DOMAIN-SUFFIX,lenzmx.com,AdBlock\n - DOMAIN-SUFFIX,lessplay.com,AdBlock\n - DOMAIN-SUFFIX,letv.irs01.com,AdBlock\n - DOMAIN-SUFFIX,leztc.com,AdBlock\n - DOMAIN-SUFFIX,lflili.com,AdBlock\n - DOMAIN-SUFFIX,lfyuanai.com,AdBlock\n - DOMAIN-SUFFIX,lg2.jointreport-switch.com,AdBlock\n - DOMAIN-SUFFIX,lg4.jointreport-switch.com,AdBlock\n - DOMAIN-SUFFIX,lhafy.com,AdBlock\n - DOMAIN-SUFFIX,lhengilin.com,AdBlock\n - DOMAIN-SUFFIX,lhusy.com,AdBlock\n - DOMAIN-SUFFIX,li.anyysz.com,AdBlock\n - DOMAIN-SUFFIX,liangao.com,AdBlock\n - DOMAIN-SUFFIX,liangziweixg.com,AdBlock\n - DOMAIN-SUFFIX,lib.haotv8.com,AdBlock\n - DOMAIN-SUFFIX,liba.haotv8.com,AdBlock\n - DOMAIN-SUFFIX,libs.tvmao.cn,AdBlock\n - DOMAIN-SUFFIX,license.lumion3d.com,AdBlock\n - DOMAIN-SUFFIX,license.lumion3d.net,AdBlock\n - DOMAIN-SUFFIX,licenses.ashampoo.com,AdBlock\n - DOMAIN-SUFFIX,licensing.tableausoftware.com,AdBlock\n - DOMAIN-SUFFIX,life.e0575.com,AdBlock\n - DOMAIN-SUFFIX,life.imagepix.org,AdBlock\n - DOMAIN-SUFFIX,lightson.vpsboard.com,AdBlock\n - DOMAIN-SUFFIX,linezing.com,AdBlock\n - DOMAIN-SUFFIX,lingdian98.com,AdBlock\n - DOMAIN-SUFFIX,linkbide.com,AdBlock\n - DOMAIN-SUFFIX,linkeye.ximalaya.com,AdBlock\n - DOMAIN-SUFFIX,linkpage.cn,AdBlock\n - DOMAIN-SUFFIX,links.services.disqus.com,AdBlock\n - DOMAIN-SUFFIX,linktech.cn,AdBlock\n - DOMAIN-SUFFIX,linyao.dxsdb.com,AdBlock\n - DOMAIN-SUFFIX,lishuanghao.com,AdBlock\n - DOMAIN-SUFFIX,listenother.com,AdBlock\n - DOMAIN-SUFFIX,listlog.baofeng.net,AdBlock\n - DOMAIN-SUFFIX,liuliguo.com,AdBlock\n - DOMAIN-SUFFIX,live.tvpot.daum.net,AdBlock\n - DOMAIN-SUFFIX,livehapp.com,AdBlock\n - DOMAIN-SUFFIX,livep.l.ott.video.qq.com,AdBlock\n - DOMAIN-SUFFIX,lives.l.cp81.ott.cibntv.net,AdBlock\n - DOMAIN-SUFFIX,lives.l.ott.video.qq.com,AdBlock\n - DOMAIN-SUFFIX,lives.l.qq.com,AdBlock\n - DOMAIN-SUFFIX,liveupdate.mac.sandai.net,AdBlock\n - DOMAIN-SUFFIX,lixiangmo.com,AdBlock\n - DOMAIN-SUFFIX,ljrtb.cn,AdBlock\n - DOMAIN-SUFFIX,lkf1.m.sanhao3.com,AdBlock\n - DOMAIN-SUFFIX,ll.a.hulu.com,AdBlock\n - DOMAIN-SUFFIX,ll.gxsky.com,AdBlock\n - DOMAIN-SUFFIX,ll.hudong.com,AdBlock\n - DOMAIN-SUFFIX,ll.songlaoban.cn,AdBlock\n - DOMAIN-SUFFIX,ll38.com,AdBlock\n - DOMAIN-SUFFIX,lm.dawenxue.org,AdBlock\n - DOMAIN-SUFFIX,lm.licenses.adobe.com,AdBlock\n - DOMAIN-SUFFIX,lm.souid.com,AdBlock\n - DOMAIN-SUFFIX,lm.xiashu.la,AdBlock\n - DOMAIN-SUFFIX,lml.jfjsp.com,AdBlock\n - DOMAIN-SUFFIX,lmlicenses.wip4.adobe.com,AdBlock\n - DOMAIN-SUFFIX,lmwap.awtks.com,AdBlock\n - DOMAIN-SUFFIX,lndjj.com,AdBlock\n - DOMAIN-SUFFIX,lnk0.com,AdBlock\n - DOMAIN-SUFFIX,lnk8z.com,AdBlock\n - DOMAIN-SUFFIX,lnr2.com,AdBlock\n - DOMAIN-SUFFIX,load77.exelator.com,AdBlock\n - DOMAIN-SUFFIX,loading.baofeng5.baofeng.net,AdBlock\n - DOMAIN-SUFFIX,loadm.exelator.com,AdBlock\n - DOMAIN-SUFFIX,loandatec.com,AdBlock\n - DOMAIN-SUFFIX,localnetwork.uop,AdBlock\n - DOMAIN-SUFFIX,localytics.com,AdBlock\n - DOMAIN-SUFFIX,location.ximalaya.com,AdBlock\n - DOMAIN-SUFFIX,locdrop.query.yahoo.com,AdBlock\n - DOMAIN-SUFFIX,log1.17173.com,AdBlock\n - DOMAIN-SUFFIX,log1.molitv.cn,AdBlock\n - DOMAIN-SUFFIX,log2.air.yoyi.com.cn,AdBlock\n - DOMAIN-SUFFIX,log2.molitv.cn,AdBlock\n - DOMAIN-SUFFIX,log-dmp.suishenyun.cn,AdBlock\n - DOMAIN-SUFFIX,logonext.tv.kuyun.com,AdBlock\n - DOMAIN-SUFFIX,logoshejishi.com,AdBlock\n - DOMAIN-SUFFIX,logstat.caixin.com,AdBlock\n - DOMAIN-SUFFIX,logupdate.avlyun.sec.miui.com,AdBlock\n - DOMAIN-SUFFIX,lol.pnhfc.com,AdBlock\n - DOMAIN-SUFFIX,loldy.jiangmg.com,AdBlock\n - DOMAIN-SUFFIX,lomark.cn,AdBlock\n - DOMAIN-SUFFIX,londonprivaterentals.standard.co.uk,AdBlock\n - DOMAIN-SUFFIX,looky.hyves.org,AdBlock\n - DOMAIN-SUFFIX,lottery.kuaiya.cn,AdBlock\n - DOMAIN-SUFFIX,lotuseed.com,AdBlock\n - DOMAIN-SUFFIX,lovestyl.com,AdBlock\n - DOMAIN-SUFFIX,lovfp.com,AdBlock\n - DOMAIN-SUFFIX,lp.jiuzhilan.com,AdBlock\n - DOMAIN-SUFFIX,lp.startapp.com,AdBlock\n - DOMAIN-SUFFIX,lp1901.com,AdBlock\n - DOMAIN-SUFFIX,lpsxssm.com,AdBlock\n - DOMAIN-SUFFIX,lqmohun.com,AdBlock\n - DOMAIN-SUFFIX,lrswl.com,AdBlock\n - DOMAIN-SUFFIX,ls.webmd.com,AdBlock\n - DOMAIN-SUFFIX,lsxmg.com,AdBlock\n - DOMAIN-SUFFIX,ltcprtc.com,AdBlock\n - DOMAIN-SUFFIX,ltheanine.cn,AdBlock\n - DOMAIN-SUFFIX,lthxz.cn,AdBlock\n - DOMAIN-SUFFIX,lu.sogou.com,AdBlock\n - DOMAIN-SUFFIX,lubosheng.cn,AdBlock\n - DOMAIN-SUFFIX,lucting.cn,AdBlock\n - DOMAIN-SUFFIX,lufax.com,AdBlock\n - DOMAIN-SUFFIX,luotediao.net,AdBlock\n - DOMAIN-SUFFIX,lvjian66.com,AdBlock\n - DOMAIN-SUFFIX,lw1.cdmediaworld.com,AdBlock\n - DOMAIN-SUFFIX,lw2.gamecopyworld.com,AdBlock\n - DOMAIN-SUFFIX,lwnne.cn,AdBlock\n - DOMAIN-SUFFIX,lwq.wangketuan.com,AdBlock\n - DOMAIN-SUFFIX,lx167.com,AdBlock\n - DOMAIN-SUFFIX,lxcdn.dl.files.xiaomi.net,AdBlock\n - DOMAIN-SUFFIX,lxqcgj.com,AdBlock\n - DOMAIN-SUFFIX,lxting.com,AdBlock\n - DOMAIN-SUFFIX,lx-upload-log.yidianzixun.com,AdBlock\n - DOMAIN-SUFFIX,lyaeccn.com,AdBlock\n - DOMAIN-SUFFIX,lyapi.1391.com,AdBlock\n - DOMAIN-SUFFIX,lycos-eu.imrworldwide.com,AdBlock\n - DOMAIN-SUFFIX,lyhdream.com,AdBlock\n - DOMAIN-SUFFIX,lyjk.1391.com,AdBlock\n - DOMAIN-SUFFIX,lynndollin.com,AdBlock\n - DOMAIN-SUFFIX,lyrymy.com,AdBlock\n - DOMAIN-SUFFIX,lytubaobao.com,AdBlock\n - DOMAIN-SUFFIX,lyunsd.cn,AdBlock\n - DOMAIN-SUFFIX,lyztdz.com,AdBlock\n - DOMAIN-SUFFIX,lz.chaelc.com,AdBlock\n - DOMAIN-SUFFIX,lz.whafwl.com,AdBlock\n - DOMAIN-SUFFIX,lzjycy.com,AdBlock\n - DOMAIN-SUFFIX,lzmm8.com,AdBlock\n - DOMAIN-SUFFIX,m.027blzs.com,AdBlock\n - DOMAIN-SUFFIX,m.0531mnk.net,AdBlock\n - DOMAIN-SUFFIX,m.107279.com,AdBlock\n - DOMAIN-SUFFIX,m.118ex.cn,AdBlock\n - DOMAIN-SUFFIX,m.1768.com,AdBlock\n - DOMAIN-SUFFIX,m.1919388.net,AdBlock\n - DOMAIN-SUFFIX,m.28487.net,AdBlock\n - DOMAIN-SUFFIX,m.3987.com,AdBlock\n - DOMAIN-SUFFIX,m.495495.com,AdBlock\n - DOMAIN-SUFFIX,m.51xmgys.com,AdBlock\n - DOMAIN-SUFFIX,m.52tushuo.com,AdBlock\n - DOMAIN-SUFFIX,m.551144.com,AdBlock\n - DOMAIN-SUFFIX,m.640640.com,AdBlock\n - DOMAIN-SUFFIX,m.649649.com,AdBlock\n - DOMAIN-SUFFIX,m.7180443.com,AdBlock\n - DOMAIN-SUFFIX,m.77vcd.com,AdBlock\n - DOMAIN-SUFFIX,m.937920.com,AdBlock\n - DOMAIN-SUFFIX,m.abfirst.cn,AdBlock\n - DOMAIN-SUFFIX,m.acaox.com,AdBlock\n - DOMAIN-SUFFIX,m.achig.com,AdBlock\n - DOMAIN-SUFFIX,m.ad.zhangyue.com,AdBlock\n - DOMAIN-SUFFIX,m.adaog.com,AdBlock\n - DOMAIN-SUFFIX,m.adxpop.com,AdBlock\n - DOMAIN-SUFFIX,m.afoux.com,AdBlock\n - DOMAIN-SUFFIX,m.anmeilai.net,AdBlock\n - DOMAIN-SUFFIX,m.anzhuotan.com,AdBlock\n - DOMAIN-SUFFIX,m.apxyz.com,AdBlock\n - DOMAIN-SUFFIX,m.aqiudaohang.com,AdBlock\n - DOMAIN-SUFFIX,m.assigned.cn,AdBlock\n - DOMAIN-SUFFIX,m.aty.cp45.ott.cibntv.net,AdBlock\n - DOMAIN-SUFFIX,m.aty.snmsohu.aisee.tv,AdBlock\n - DOMAIN-SUFFIX,m.axsre.com,AdBlock\n - DOMAIN-SUFFIX,m.baidu.com.yiqisee.cn,AdBlock\n - DOMAIN-SUFFIX,m.baidu.com.zhiduo.org,AdBlock\n - DOMAIN-SUFFIX,m.bailingjiankang.com,AdBlock\n - DOMAIN-SUFFIX,m.baiyangzs.com,AdBlock\n - DOMAIN-SUFFIX,m.bapkt.com,AdBlock\n - DOMAIN-SUFFIX,m.bbvjs.com,AdBlock\n - DOMAIN-SUFFIX,m.bdiae.com,AdBlock\n - DOMAIN-SUFFIX,m.beacon.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,m.bentengcn.com,AdBlock\n - DOMAIN-SUFFIX,m.biquge5200.cc,AdBlock\n - DOMAIN-SUFFIX,m.bokanedu.net,AdBlock\n - DOMAIN-SUFFIX,m.bsnnk.com,AdBlock\n - DOMAIN-SUFFIX,m.bss.pandora.xiaomi.com,AdBlock\n - DOMAIN-SUFFIX,m.bvoer.com,AdBlock\n - DOMAIN-SUFFIX,m.bvosv.com,AdBlock\n - DOMAIN-SUFFIX,m.casbanlly.com,AdBlock\n - DOMAIN-SUFFIX,m.cbeif.com,AdBlock\n - DOMAIN-SUFFIX,m.ccunf.com,AdBlock\n - DOMAIN-SUFFIX,m.cdfzcz.com,AdBlock\n - DOMAIN-SUFFIX,m.cenrs.com,AdBlock\n - DOMAIN-SUFFIX,m.chenhuia.com,AdBlock\n - DOMAIN-SUFFIX,m.chexiw.com,AdBlock\n - DOMAIN-SUFFIX,m.chfuw.com,AdBlock\n - DOMAIN-SUFFIX,m.cjieh.com,AdBlock\n - DOMAIN-SUFFIX,m.ckikq.com,AdBlock\n - DOMAIN-SUFFIX,m.clkservice.youdao.com,AdBlock\n - DOMAIN-SUFFIX,m.cocounion.com,AdBlock\n - DOMAIN-SUFFIX,m.codlw.com,AdBlock\n - DOMAIN-SUFFIX,m.coenr.com,AdBlock\n - DOMAIN-SUFFIX,m.couas.com,AdBlock\n - DOMAIN-SUFFIX,m.cqytjzgc.com,AdBlock\n - DOMAIN-SUFFIX,m.ctsywy.com,AdBlock\n - DOMAIN-SUFFIX,m.cudaojia.com,AdBlock\n - DOMAIN-SUFFIX,m.cuoas.com,AdBlock\n - DOMAIN-SUFFIX,m.cuoss.com,AdBlock\n - DOMAIN-SUFFIX,m.daishuxy.com,AdBlock\n - DOMAIN-SUFFIX,m.dante2007.com,AdBlock\n - DOMAIN-SUFFIX,m.data.mob.com,AdBlock\n - DOMAIN-SUFFIX,m.dbaiz.com,AdBlock\n - DOMAIN-SUFFIX,m.dgaoz.com,AdBlock\n - DOMAIN-SUFFIX,m.diogv.com,AdBlock\n - DOMAIN-SUFFIX,m.djhhy.com,AdBlock\n - DOMAIN-SUFFIX,m.dnfeu.com,AdBlock\n - DOMAIN-SUFFIX,m.doodlemobile.com,AdBlock\n - DOMAIN-SUFFIX,m.dsjre.com,AdBlock\n - DOMAIN-SUFFIX,m.du1du.org,AdBlock\n - DOMAIN-SUFFIX,m.duias.com,AdBlock\n - DOMAIN-SUFFIX,m.duobao999.com,AdBlock\n - DOMAIN-SUFFIX,m.dxmci.com,AdBlock\n - DOMAIN-SUFFIX,m.edo5.com,AdBlock\n - DOMAIN-SUFFIX,m.ee-skin.com,AdBlock\n - DOMAIN-SUFFIX,m.ee-vip.net,AdBlock\n - DOMAIN-SUFFIX,m.efeiy.com,AdBlock\n - DOMAIN-SUFFIX,m.ehxyz.com,AdBlock\n - DOMAIN-SUFFIX,m.emgwq.com,AdBlock\n - DOMAIN-SUFFIX,m.enjuk.com,AdBlock\n - DOMAIN-SUFFIX,m.ennmt.com,AdBlock\n - DOMAIN-SUFFIX,m.fbaix.com,AdBlock\n - DOMAIN-SUFFIX,m.fbaot.com,AdBlock\n - DOMAIN-SUFFIX,m.fcaot.com,AdBlock\n - DOMAIN-SUFFIX,m.fcuit.com,AdBlock\n - DOMAIN-SUFFIX,m.fecjf.cn,AdBlock\n - DOMAIN-SUFFIX,m.feirs.com,AdBlock\n - DOMAIN-SUFFIX,m.fengwanwl.com,AdBlock\n - DOMAIN-SUFFIX,m.fenrs.com,AdBlock\n - DOMAIN-SUFFIX,m.fhxsw.org,AdBlock\n - DOMAIN-SUFFIX,m.fimky.com,AdBlock\n - DOMAIN-SUFFIX,m.fkkse.com,AdBlock\n - DOMAIN-SUFFIX,m.fkogs.com,AdBlock\n - DOMAIN-SUFFIX,m.focuscat.com,AdBlock\n - DOMAIN-SUFFIX,m.fouas.com,AdBlock\n - DOMAIN-SUFFIX,m.foumm.com,AdBlock\n - DOMAIN-SUFFIX,m.fstaw.com,AdBlock\n - DOMAIN-SUFFIX,m.fwjoi.com,AdBlock\n - DOMAIN-SUFFIX,m.fxbga.com,AdBlock\n - DOMAIN-SUFFIX,m.fzyda.com,AdBlock\n - DOMAIN-SUFFIX,m.gameyun907.net,AdBlock\n - DOMAIN-SUFFIX,m.ganrs.com,AdBlock\n - DOMAIN-SUFFIX,m.gbieg.com,AdBlock\n - DOMAIN-SUFFIX,m.gcaij.com,AdBlock\n - DOMAIN-SUFFIX,m.gcheg.com,AdBlock\n - DOMAIN-SUFFIX,m.gdt.vip1790.cn,AdBlock\n - DOMAIN-SUFFIX,m.gglay.com,AdBlock\n - DOMAIN-SUFFIX,m.gtiou.com,AdBlock\n - DOMAIN-SUFFIX,m.gtnde.com,AdBlock\n - DOMAIN-SUFFIX,m.guaas.com,AdBlock\n - DOMAIN-SUFFIX,m.guanren11.com,AdBlock\n - DOMAIN-SUFFIX,m.guanren5.com,AdBlock\n - DOMAIN-SUFFIX,m.guanren6.com,AdBlock\n - DOMAIN-SUFFIX,m.guanren9.com,AdBlock\n - DOMAIN-SUFFIX,m.guifei99.com,AdBlock\n - DOMAIN-SUFFIX,m.gujinyue.com,AdBlock\n - DOMAIN-SUFFIX,m.gwdqp.com,AdBlock\n - DOMAIN-SUFFIX,m.gxkyl.com,AdBlock\n - DOMAIN-SUFFIX,m.haowj.com.cn,AdBlock\n - DOMAIN-SUFFIX,m.harbinbaojia.net,AdBlock\n - DOMAIN-SUFFIX,m.hellomingpian.com,AdBlock\n - DOMAIN-SUFFIX,m.heygugu.com,AdBlock\n - DOMAIN-SUFFIX,m.hhllyt.com,AdBlock\n - DOMAIN-SUFFIX,m.hissq.com,AdBlock\n - DOMAIN-SUFFIX,m.hk7799.net,AdBlock\n - DOMAIN-SUFFIX,m.hkmqp.com,AdBlock\n - DOMAIN-SUFFIX,m.hmzsfmjc.com,AdBlock\n - DOMAIN-SUFFIX,m.hogyp.com,AdBlock\n - DOMAIN-SUFFIX,m.hot-mob.com,AdBlock\n - DOMAIN-SUFFIX,m.hpfjy.com,AdBlock\n - DOMAIN-SUFFIX,m.hpzyl.com,AdBlock\n - DOMAIN-SUFFIX,m.hsbkr.com,AdBlock\n - DOMAIN-SUFFIX,m.htper.com,AdBlock\n - DOMAIN-SUFFIX,m.huanyuexpress.com,AdBlock\n - DOMAIN-SUFFIX,m.huyulh.com,AdBlock\n - DOMAIN-SUFFIX,m.hyzui.com,AdBlock\n - DOMAIN-SUFFIX,m.icyrd.com,AdBlock\n - DOMAIN-SUFFIX,m.ienkdaged.cn,AdBlock\n - DOMAIN-SUFFIX,m.ienkdago.cn,AdBlock\n - DOMAIN-SUFFIX,m.infvb.com,AdBlock\n - DOMAIN-SUFFIX,m.irauz.com,AdBlock\n - DOMAIN-SUFFIX,m.irkuj.com,AdBlock\n - DOMAIN-SUFFIX,m.iruad.com,AdBlock\n - DOMAIN-SUFFIX,m.ishowms.com,AdBlock\n - DOMAIN-SUFFIX,m.jcwwxn.com,AdBlock\n - DOMAIN-SUFFIX,m.jdaot.com,AdBlock\n - DOMAIN-SUFFIX,m.jgkto.com,AdBlock\n - DOMAIN-SUFFIX,m.jhcgood.com,AdBlock\n - DOMAIN-SUFFIX,m.jieyixiu.com,AdBlock\n - DOMAIN-SUFFIX,m.jiirz.com,AdBlock\n - DOMAIN-SUFFIX,m.jinchaoyu.com,AdBlock\n - DOMAIN-SUFFIX,m.jioeg.com,AdBlock\n - DOMAIN-SUFFIX,m.jkert.com,AdBlock\n - DOMAIN-SUFFIX,m.jlkja.com,AdBlock\n - DOMAIN-SUFFIX,m.jltdbyq.com,AdBlock\n - DOMAIN-SUFFIX,m.joyxv.com,AdBlock\n - DOMAIN-SUFFIX,m.juyzr.com,AdBlock\n - DOMAIN-SUFFIX,m.jwiyr.com,AdBlock\n - DOMAIN-SUFFIX,m.jyhwt.cn,AdBlock\n - DOMAIN-SUFFIX,m.kcooy.com,AdBlock\n - DOMAIN-SUFFIX,m.kejet.net,AdBlock\n - DOMAIN-SUFFIX,m.kewro.com,AdBlock\n - DOMAIN-SUFFIX,m.khuoy.com,AdBlock\n - DOMAIN-SUFFIX,m.kjfhe.com,AdBlock\n - DOMAIN-SUFFIX,m.kjhfy.com,AdBlock\n - DOMAIN-SUFFIX,m.kl6636.net,AdBlock\n - DOMAIN-SUFFIX,m.ksttwz.com,AdBlock\n - DOMAIN-SUFFIX,m.kubiqq.com,AdBlock\n - DOMAIN-SUFFIX,m.kwjkd.com,AdBlock\n - DOMAIN-SUFFIX,m.kxhie.com,AdBlock\n - DOMAIN-SUFFIX,m.laigame7.net,AdBlock\n - DOMAIN-SUFFIX,m.lancedu.com,AdBlock\n - DOMAIN-SUFFIX,m.laojiayoufang.com,AdBlock\n - DOMAIN-SUFFIX,m.laoqu123.com,AdBlock\n - DOMAIN-SUFFIX,m.lfdydk.com,AdBlock\n - DOMAIN-SUFFIX,m.lovezhishou.com,AdBlock\n - DOMAIN-SUFFIX,m.lusrg.cn,AdBlock\n - DOMAIN-SUFFIX,m.lyjz001.com,AdBlock\n - DOMAIN-SUFFIX,m.lzida.com,AdBlock\n - DOMAIN-SUFFIX,m.lzytt.com,AdBlock\n - DOMAIN-SUFFIX,m.maopuzw.com,AdBlock\n - DOMAIN-SUFFIX,m.mgogo.com,AdBlock\n - DOMAIN-SUFFIX,m.mgsue.cn,AdBlock\n - DOMAIN-SUFFIX,m.miaoxinqipei.com,AdBlock\n - DOMAIN-SUFFIX,m.mightiger.net,AdBlock\n - DOMAIN-SUFFIX,m.miiuv.com,AdBlock\n - DOMAIN-SUFFIX,m.miupp.com,AdBlock\n - DOMAIN-SUFFIX,m.mmkvi.com,AdBlock\n - DOMAIN-SUFFIX,m.mouaa.com,AdBlock\n - DOMAIN-SUFFIX,m.mqgpo.com,AdBlock\n - DOMAIN-SUFFIX,m.mrtuo.com,AdBlock\n - DOMAIN-SUFFIX,m.mtuoa.com,AdBlock\n - DOMAIN-SUFFIX,m.mushizhubao.com,AdBlock\n - DOMAIN-SUFFIX,m.mxguan.com,AdBlock\n - DOMAIN-SUFFIX,m.nduop.com,AdBlock\n - DOMAIN-SUFFIX,m.neijh.com,AdBlock\n - DOMAIN-SUFFIX,m.nejup.com,AdBlock\n - DOMAIN-SUFFIX,m.nernv.com,AdBlock\n - DOMAIN-SUFFIX,m.nfkos.com,AdBlock\n - DOMAIN-SUFFIX,m.niegg.com,AdBlock\n - DOMAIN-SUFFIX,m.nmtouzi.com,AdBlock\n - DOMAIN-SUFFIX,m.nnfiy.com,AdBlock\n - DOMAIN-SUFFIX,m.nouaa.com,AdBlock\n - DOMAIN-SUFFIX,m.nthtcs.com,AdBlock\n - DOMAIN-SUFFIX,m.ntxiangtai.com,AdBlock\n - DOMAIN-SUFFIX,m.nuxyz.cn,AdBlock\n - DOMAIN-SUFFIX,m.nwxzs.com,AdBlock\n - DOMAIN-SUFFIX,m.nxypz.com,AdBlock\n - DOMAIN-SUFFIX,m.oesnw.com,AdBlock\n - DOMAIN-SUFFIX,m.opqsr.com,AdBlock\n - DOMAIN-SUFFIX,m.osndy.com,AdBlock\n - DOMAIN-SUFFIX,m.ourlj.com,AdBlock\n - DOMAIN-SUFFIX,m.oyrim.com,AdBlock\n - DOMAIN-SUFFIX,m.panda.voiceads.cn,AdBlock\n - DOMAIN-SUFFIX,m.pbino.com,AdBlock\n - DOMAIN-SUFFIX,m.phonthing.com,AdBlock\n - DOMAIN-SUFFIX,m.picbr.com,AdBlock\n - DOMAIN-SUFFIX,m.pieaa.com,AdBlock\n - DOMAIN-SUFFIX,m.plerv.com,AdBlock\n - DOMAIN-SUFFIX,m.pomkl.com,AdBlock\n - DOMAIN-SUFFIX,m.poonscn.com,AdBlock\n - DOMAIN-SUFFIX,m.pougg.com,AdBlock\n - DOMAIN-SUFFIX,m.prazpf.cn,AdBlock\n - DOMAIN-SUFFIX,m.pubbirdf.com,AdBlock\n - DOMAIN-SUFFIX,m.puooi.com,AdBlock\n - DOMAIN-SUFFIX,m.pwjhg.com,AdBlock\n - DOMAIN-SUFFIX,m.pyerc.com,AdBlock\n - DOMAIN-SUFFIX,m.qcw.com,AdBlock\n - DOMAIN-SUFFIX,m.qhuik.com,AdBlock\n - DOMAIN-SUFFIX,m.qianka.com,AdBlock\n - DOMAIN-SUFFIX,m.qingzhencai.net,AdBlock\n - DOMAIN-SUFFIX,m.qiyunmuye.com,AdBlock\n - DOMAIN-SUFFIX,m.qsove.com,AdBlock\n - DOMAIN-SUFFIX,m.qulishi.com,AdBlock\n - DOMAIN-SUFFIX,m.qusub.com,AdBlock\n - DOMAIN-SUFFIX,m.qvxyz.com,AdBlock\n - DOMAIN-SUFFIX,m.rhcapass.com,AdBlock\n - DOMAIN-SUFFIX,m.ricpt.com,AdBlock\n - DOMAIN-SUFFIX,m.rmuqvq.cn,AdBlock\n - DOMAIN-SUFFIX,m.rmwdn.com,AdBlock\n - DOMAIN-SUFFIX,m.romgv.com,AdBlock\n - DOMAIN-SUFFIX,m.rrsdl.com,AdBlock\n - DOMAIN-SUFFIX,m.rwganw.cn,AdBlock\n - DOMAIN-SUFFIX,m.sanitwealth.com,AdBlock\n - DOMAIN-SUFFIX,m.sanjiangge.com,AdBlock\n - DOMAIN-SUFFIX,m.sbenx.com,AdBlock\n - DOMAIN-SUFFIX,m.sbinx.com,AdBlock\n - DOMAIN-SUFFIX,m.sewxi.com,AdBlock\n - DOMAIN-SUFFIX,m.shenyunkeji.com,AdBlock\n - DOMAIN-SUFFIX,m.simba.taobao.com,AdBlock\n - DOMAIN-SUFFIX,m.sjaidu.com,AdBlock\n - DOMAIN-SUFFIX,m.sjuqc.com,AdBlock\n - DOMAIN-SUFFIX,m.sjzhushou.com,AdBlock\n - DOMAIN-SUFFIX,m.smsksx.com,AdBlock\n - DOMAIN-SUFFIX,m.sosjyx.com,AdBlock\n - DOMAIN-SUFFIX,m.srrux.com,AdBlock\n - DOMAIN-SUFFIX,m.suehy.com,AdBlock\n - DOMAIN-SUFFIX,m.sxxca.com,AdBlock\n - DOMAIN-SUFFIX,m.symaa.cn,AdBlock\n - DOMAIN-SUFFIX,m.symab.cn,AdBlock\n - DOMAIN-SUFFIX,m.symac.cn,AdBlock\n - DOMAIN-SUFFIX,m.symad.cn,AdBlock\n - DOMAIN-SUFFIX,m.symag.cn,AdBlock\n - DOMAIN-SUFFIX,m.symaj.cn,AdBlock\n - DOMAIN-SUFFIX,m.szqifu.com,AdBlock\n - DOMAIN-SUFFIX,m.tansuotv.com,AdBlock\n - DOMAIN-SUFFIX,m.tcksbz888.com,AdBlock\n - DOMAIN-SUFFIX,m.tiantianedu.net,AdBlock\n - DOMAIN-SUFFIX,m.tiaopimiao.net,AdBlock\n - DOMAIN-SUFFIX,m.tick0.com,AdBlock\n - DOMAIN-SUFFIX,m.tiojk.com,AdBlock\n - DOMAIN-SUFFIX,m.tuopp.com,AdBlock\n - DOMAIN-SUFFIX,m.twldmx.com,AdBlock\n - DOMAIN-SUFFIX,m.txtxr.com,AdBlock\n - DOMAIN-SUFFIX,m.uc123.com,AdBlock\n - DOMAIN-SUFFIX,m.uczzd.cn,AdBlock\n - DOMAIN-SUFFIX,m.ueram.com,AdBlock\n - DOMAIN-SUFFIX,m.uissm.com,AdBlock\n - DOMAIN-SUFFIX,m.vaxyz.com,AdBlock\n - DOMAIN-SUFFIX,m.vbaou.com,AdBlock\n - DOMAIN-SUFFIX,m.vbieu.com,AdBlock\n - DOMAIN-SUFFIX,m.vbinu.com,AdBlock\n - DOMAIN-SUFFIX,m.verpt.com,AdBlock\n - DOMAIN-SUFFIX,m.vichc.com,AdBlock\n - DOMAIN-SUFFIX,m.vouky.com,AdBlock\n - DOMAIN-SUFFIX,m.vpon.com,AdBlock\n - DOMAIN-SUFFIX,m.vsxet.com,AdBlock\n - DOMAIN-SUFFIX,m.wcjup.com,AdBlock\n - DOMAIN-SUFFIX,m.weboser.com,AdBlock\n - DOMAIN-SUFFIX,m.weixingshexiangji.net,AdBlock\n - DOMAIN-SUFFIX,m.wervp.com,AdBlock\n - DOMAIN-SUFFIX,m.wgewj.cn,AdBlock\n - DOMAIN-SUFFIX,m.wikigifth.com,AdBlock\n - DOMAIN-SUFFIX,m.wjhehaofc.com,AdBlock\n - DOMAIN-SUFFIX,m.wkjhd.com,AdBlock\n - DOMAIN-SUFFIX,m.wnxcg.com,AdBlock\n - DOMAIN-SUFFIX,m.wonwg.com,AdBlock\n - DOMAIN-SUFFIX,m.wooboo.com.cn,AdBlock\n - DOMAIN-SUFFIX,m.wrating.com,AdBlock\n - DOMAIN-SUFFIX,m.wshufa.com,AdBlock\n - DOMAIN-SUFFIX,m.wsxxu.com,AdBlock\n - DOMAIN-SUFFIX,m.wuqutu.com,AdBlock\n - DOMAIN-SUFFIX,m.wxhh678.com,AdBlock\n - DOMAIN-SUFFIX,m.xcy8.com,AdBlock\n - DOMAIN-SUFFIX,m.xdkje.com,AdBlock\n - DOMAIN-SUFFIX,m.xeihy.com,AdBlock\n - DOMAIN-SUFFIX,m.xetvb.com,AdBlock\n - DOMAIN-SUFFIX,m.xhaiu.com,AdBlock\n - DOMAIN-SUFFIX,m.xiangchim0.com,AdBlock\n - DOMAIN-SUFFIX,m.xikdn.com,AdBlock\n - DOMAIN-SUFFIX,m.xingxd.com,AdBlock\n - DOMAIN-SUFFIX,m.xkqpco.com,AdBlock\n - DOMAIN-SUFFIX,m.xkqpco.com.com,AdBlock\n - DOMAIN-SUFFIX,m.xlsschina15.net,AdBlock\n - DOMAIN-SUFFIX,m.xmgysweb.com,AdBlock\n - DOMAIN-SUFFIX,m.xpjis.com,AdBlock\n - DOMAIN-SUFFIX,m.xxkio.com,AdBlock\n - DOMAIN-SUFFIX,m.yalayi.com,AdBlock\n - DOMAIN-SUFFIX,m.yangjingbang.net,AdBlock\n - DOMAIN-SUFFIX,m.yicang8.com,AdBlock\n - DOMAIN-SUFFIX,m.yingchengtou.com,AdBlock\n - DOMAIN-SUFFIX,m.ynnke.com,AdBlock\n - DOMAIN-SUFFIX,m.yoiur.com,AdBlock\n - DOMAIN-SUFFIX,m.yooli.com,AdBlock\n - DOMAIN-SUFFIX,m.youweiprint.com,AdBlock\n - DOMAIN-SUFFIX,m.yoyi.com.cn,AdBlock\n - DOMAIN-SUFFIX,m.ysdhe.com,AdBlock\n - DOMAIN-SUFFIX,m.yuandajiayuan.com,AdBlock\n - DOMAIN-SUFFIX,m.yuxyz.com,AdBlock\n - DOMAIN-SUFFIX,m.ywbwsm.com,AdBlock\n - DOMAIN-SUFFIX,m.yyeks.com,AdBlock\n - DOMAIN-SUFFIX,m.yyjhf.com,AdBlock\n - DOMAIN-SUFFIX,m.yzjlsb.com,AdBlock\n - DOMAIN-SUFFIX,m.zabxb.com,AdBlock\n - DOMAIN-SUFFIX,m.zaoss.com,AdBlock\n - DOMAIN-SUFFIX,m.zeiaa.com,AdBlock\n - DOMAIN-SUFFIX,m.zenffs.cn,AdBlock\n - DOMAIN-SUFFIX,m.zenwq.com,AdBlock\n - DOMAIN-SUFFIX,m.zhuyuanp.club,AdBlock\n - DOMAIN-SUFFIX,m.zhuyuanp.shop,AdBlock\n - DOMAIN-SUFFIX,m.zhuyuanp.top,AdBlock\n - DOMAIN-SUFFIX,m.zkwsdf.com,AdBlock\n - DOMAIN-SUFFIX,m.zougg.com,AdBlock\n - DOMAIN-SUFFIX,m.zuopp.com,AdBlock\n - DOMAIN-SUFFIX,m1.baidu.com,AdBlock\n - DOMAIN-SUFFIX,m1.daumcdn.net,AdBlock\n - DOMAIN-SUFFIX,m1.mgogo.com,AdBlock\n - DOMAIN-SUFFIX,m1.xcy8.com,AdBlock\n - DOMAIN-SUFFIX,m2.qinsx.cn,AdBlock\n - DOMAIN-SUFFIX,m3bnqqqw.com,AdBlock\n - DOMAIN-SUFFIX,m5.apk.67mo.com,AdBlock\n - DOMAIN-SUFFIX,m9.xcdf.cn,AdBlock\n - DOMAIN-SUFFIX,m9.xcy8.com,AdBlock\n - DOMAIN-SUFFIX,ma.baidu.com,AdBlock\n - DOMAIN-SUFFIX,ma1.meishij.net,AdBlock\n - DOMAIN-SUFFIX,ma2.meishij.net,AdBlock\n - DOMAIN-SUFFIX,maccms.tan5858.com,AdBlock\n - DOMAIN-SUFFIX,mackeeper.com,AdBlock\n - DOMAIN-SUFFIX,macplatform.wondershare.com,AdBlock\n - DOMAIN-SUFFIX,mad.kuuad.com,AdBlock\n - DOMAIN-SUFFIX,mad.m.maxthon.cn,AdBlock\n - DOMAIN-SUFFIX,m-adash.m.taobao.com,AdBlock\n - DOMAIN-SUFFIX,madhouse.cn,AdBlock\n - DOMAIN-SUFFIX,madmini.com,AdBlock\n - DOMAIN-SUFFIX,mads.amazon.com,AdBlock\n - DOMAIN-SUFFIX,mads.aol.com,AdBlock\n - DOMAIN-SUFFIX,mads.dailymail.co.uk,AdBlock\n - DOMAIN-SUFFIX,madserving.com,AdBlock\n - DOMAIN-SUFFIX,magicwindow.cn,AdBlock\n - DOMAIN-SUFFIX,magnetic.t.domdex.com,AdBlock\n - DOMAIN-SUFFIX,maibahe300cc.com,AdBlock\n - DOMAIN-SUFFIX,main.exdynsrv.com,AdBlock\n - DOMAIN-SUFFIX,main.exoclick.com,AdBlock\n - DOMAIN-SUFFIX,mainbx.com,AdBlock\n - DOMAIN-SUFFIX,maipinshangmao.com,AdBlock\n - DOMAIN-SUFFIX,mairuan.cn,AdBlock\n - DOMAIN-SUFFIX,mairuan.com,AdBlock\n - DOMAIN-SUFFIX,mairuan.com.cn,AdBlock\n - DOMAIN-SUFFIX,mairuan.net,AdBlock\n - DOMAIN-SUFFIX,mairuanwang.com,AdBlock\n - DOMAIN-SUFFIX,maisoncherry.com,AdBlock\n - DOMAIN-SUFFIX,makeding.com,AdBlock\n - DOMAIN-SUFFIX,malacca.inveno.com,AdBlock\n - DOMAIN-SUFFIX,manage.wdfans.cn,AdBlock\n - DOMAIN-SUFFIX,maomaotang.com,AdBlock\n - DOMAIN-SUFFIX,map.dxpmedia.com,AdBlock\n - DOMAIN-SUFFIX,map.media6degrees.com,AdBlock\n - DOMAIN-SUFFIX,mapping.yoyi.com.cn,AdBlock\n - DOMAIN-SUFFIX,market.178.com,AdBlock\n - DOMAIN-SUFFIX,market.21cn.com,AdBlock\n - DOMAIN-SUFFIX,market.52pk.com,AdBlock\n - DOMAIN-SUFFIX,market.duowan.com,AdBlock\n - DOMAIN-SUFFIX,marketgid.com,AdBlock\n - DOMAIN-SUFFIX,marketing.888.com,AdBlock\n - DOMAIN-SUFFIX,marketing.etouch.cn,AdBlock\n - DOMAIN-SUFFIX,marketingsolutions.yahoo.com,AdBlock\n - DOMAIN-SUFFIX,marketo.com,AdBlock\n - DOMAIN-SUFFIX,marketo.net,AdBlock\n - DOMAIN-SUFFIX,masdk.3g.qq.com,AdBlock\n - DOMAIN-SUFFIX,maskbaby.com.cn,AdBlock\n - DOMAIN-SUFFIX,mass.mall044.com,AdBlock\n - DOMAIN-SUFFIX,master.wap.dphub.sandai.net,AdBlock\n - DOMAIN-SUFFIX,match.adsby.bidtheatre.com,AdBlock\n - DOMAIN-SUFFIX,match.c8.net.ua,AdBlock\n - DOMAIN-SUFFIX,match.p4p.1688.com,AdBlock\n - DOMAIN-SUFFIX,match.prod.bidr.io,AdBlock\n - DOMAIN-SUFFIX,match.rundsp.com,AdBlock\n - DOMAIN-SUFFIX,matching.targeterra.com,AdBlock\n - DOMAIN-SUFFIX,material.istreamsche.com,AdBlock\n - DOMAIN-SUFFIX,material.mtty.xin,AdBlock\n - DOMAIN-SUFFIX,mathtag.com,AdBlock\n - DOMAIN-SUFFIX,mathtype.cn,AdBlock\n - DOMAIN-SUFFIX,maw.wnbfw.com,AdBlock\n - DOMAIN-SUFFIX,maxwebsearch.com,AdBlock\n - DOMAIN-SUFFIX,maysunmedia.com,AdBlock\n - DOMAIN-SUFFIX,mb.hockeybuzz.com,AdBlock\n - DOMAIN-SUFFIX,mb.yidianzixun.com,AdBlock\n - DOMAIN-SUFFIX,mb.zam.com,AdBlock\n - DOMAIN-SUFFIX,mbai.cn,AdBlock\n - DOMAIN-SUFFIX,mbd.weathercn.com,AdBlock\n - DOMAIN-SUFFIX,mbrowser.news.haosou.com,AdBlock\n - DOMAIN-SUFFIX,mbrowser.news.so.com,AdBlock\n - DOMAIN-SUFFIX,mbs.weathercn.com,AdBlock\n - DOMAIN-SUFFIX,mc.yandex.ru,AdBlock\n - DOMAIN-SUFFIX,mclick.simba.taobao.com,AdBlock\n - DOMAIN-SUFFIX,mcore.vcgame.cn,AdBlock\n - DOMAIN-SUFFIX,md.1drj.com,AdBlock\n - DOMAIN-SUFFIX,md.he9630.com,AdBlock\n - DOMAIN-SUFFIX,md.sh5e.com,AdBlock\n - DOMAIN-SUFFIX,md0z4dh.com,AdBlock\n - DOMAIN-SUFFIX,mdc.meitustat.com,AdBlock\n - DOMAIN-SUFFIX,mdotm.com,AdBlock\n - DOMAIN-SUFFIX,mdpjnppsbjv.bid,AdBlock\n - DOMAIN-SUFFIX,mdrecv.app.cntvwb.cn,AdBlock\n - DOMAIN-SUFFIX,me.afp.chinanews.com,AdBlock\n - DOMAIN-SUFFIX,mealsandsteals.sandiego6.com,AdBlock\n - DOMAIN-SUFFIX,me-cdn.effectivemeasure.net,AdBlock\n - DOMAIN-SUFFIX,med.heyzap.com,AdBlock\n - DOMAIN-SUFFIX,medal.blog.csdn.net,AdBlock\n - DOMAIN-SUFFIX,media.2011.8684.com,AdBlock\n - DOMAIN-SUFFIX,media.cheshi-img.com,AdBlock\n - DOMAIN-SUFFIX,media.fastclick.net,AdBlock\n - DOMAIN-SUFFIX,media.jointreport-switch.com,AdBlock\n - DOMAIN-SUFFIX,media.tianjimedia.com,AdBlock\n - DOMAIN-SUFFIX,media.trafficfactory.biz,AdBlock\n - DOMAIN-SUFFIX,media.trafficjunky.net,AdBlock\n - DOMAIN-SUFFIX,media8.cn,AdBlock\n - DOMAIN-SUFFIX,mediamgr.ugo.com,AdBlock\n - DOMAIN-SUFFIX,mediaplex.com,AdBlock\n - DOMAIN-SUFFIX,mediapro.pro.cn,AdBlock\n - DOMAIN-SUFFIX,media-static.jointreport-switch.com,AdBlock\n - DOMAIN-SUFFIX,mediav.com,AdBlock\n - DOMAIN-SUFFIX,medrx.telstra.com.au,AdBlock\n - DOMAIN-SUFFIX,megajoy.com,AdBlock\n - DOMAIN-SUFFIX,meimeidaren.com,AdBlock\n - DOMAIN-SUFFIX,meiti1.net,AdBlock\n - DOMAIN-SUFFIX,meitubeauty.meitudata.com,AdBlock\n - DOMAIN-SUFFIX,meitumq.com,AdBlock\n - DOMAIN-SUFFIX,menghuanzs.com,AdBlock\n - DOMAIN-SUFFIX,mengmengdas.com,AdBlock\n - DOMAIN-SUFFIX,mengyuanwei.com,AdBlock\n - DOMAIN-SUFFIX,message.meitu.com,AdBlock\n - DOMAIN-SUFFIX,metok.sys.miui.com,AdBlock\n - DOMAIN-SUFFIX,metrics.cnn.com,AdBlock\n - DOMAIN-SUFFIX,mfan.iclick.com.cn,AdBlock\n - DOMAIN-SUFFIX,mfm.video.qq.com,AdBlock\n - DOMAIN-SUFFIX,mfp.deliver.ifeng.com,AdBlock\n - DOMAIN-SUFFIX,mfsr.lenovomm.com,AdBlock\n - DOMAIN-SUFFIX,mg.5pk,AdBlock\n - DOMAIN-SUFFIX,mg.games.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,mg.yadro.ru,AdBlock\n - DOMAIN-SUFFIX,mgid.com,AdBlock\n - DOMAIN-SUFFIX,mgldzcls.com,AdBlock\n - DOMAIN-SUFFIX,mgogo.com,AdBlock\n - DOMAIN-SUFFIX,mgwcn.com,AdBlock\n - DOMAIN-SUFFIX,mgwl668.com,AdBlock\n - DOMAIN-SUFFIX,mhd.1391.com,AdBlock\n - DOMAIN-SUFFIX,mhdpay.1391.com,AdBlock\n - DOMAIN-SUFFIX,mhdtestks3.1391.com,AdBlock\n - DOMAIN-SUFFIX,mhdufile.1391.com,AdBlock\n - DOMAIN-SUFFIX,mhjk.1391.com,AdBlock\n - DOMAIN-SUFFIX,mhuodong.elong.com,AdBlock\n - DOMAIN-SUFFIX,miam4.cn,AdBlock\n - DOMAIN-SUFFIX,miaobeichina.com,AdBlock\n - DOMAIN-SUFFIX,miaozhen.com,AdBlock\n - DOMAIN-SUFFIX,mibook-10006092.cos.myqcloud.com,AdBlock\n - DOMAIN-SUFFIX,microad-cn.com,AdBlock\n - DOMAIN-SUFFIX,mid.houyi.baofeng.net,AdBlock\n - DOMAIN-SUFFIX,midas.rong360.com,AdBlock\n - DOMAIN-SUFFIX,midinfo.baofeng.com,AdBlock\n - DOMAIN-SUFFIX,mie99.net,AdBlock\n - DOMAIN-SUFFIX,migc.g.mi.com,AdBlock\n - DOMAIN-SUFFIX,migcreport.g.mi.com,AdBlock\n - DOMAIN-SUFFIX,migrate.driveapi.micloud.xiaomi.net,AdBlock\n - DOMAIN-SUFFIX,migu.kssws.ks-cdn.com,AdBlock\n - DOMAIN-SUFFIX,mihui.com,AdBlock\n - DOMAIN-SUFFIX,miidi.net,AdBlock\n - DOMAIN-SUFFIX,mijifen.com,AdBlock\n - DOMAIN-SUFFIX,milk.yesky.com.cn,AdBlock\n - DOMAIN-SUFFIX,millennialmedia.com,AdBlock\n - DOMAIN-SUFFIX,millwardbrownacsr.com,AdBlock\n - DOMAIN-SUFFIX,mimg.126.net,AdBlock\n - DOMAIN-SUFFIX,mimg.7791.com.cn,AdBlock\n - DOMAIN-SUFFIX,mindmanager.cc,AdBlock\n - DOMAIN-SUFFIX,mindmapper.cc,AdBlock\n - DOMAIN-SUFFIX,minesage.com,AdBlock\n - DOMAIN-SUFFIX,minfo.wps.cn,AdBlock\n - DOMAIN-SUFFIX,mingxianshanghang.cn,AdBlock\n - DOMAIN-SUFFIX,mingysh.com,AdBlock\n - DOMAIN-SUFFIX,mini.cpc.sogou.com,AdBlock\n - DOMAIN-SUFFIX,mini.eastday.com,AdBlock\n - DOMAIN-SUFFIX,mini.hao123.com,AdBlock\n - DOMAIN-SUFFIX,mini.jijiplayer.com,AdBlock\n - DOMAIN-SUFFIX,mini2015.qq.com,AdBlock\n - DOMAIN-SUFFIX,minidcsc.kugou.com,AdBlock\n - DOMAIN-SUFFIX,minipage.2345.com,AdBlock\n - DOMAIN-SUFFIX,minisite.vidown.cn,AdBlock\n - DOMAIN-SUFFIX,minisplat.cn,AdBlock\n - DOMAIN-SUFFIX,miniye.xjts.cn,AdBlock\n - DOMAIN-SUFFIX,mip.yuelvxing.com,AdBlock\n - DOMAIN-SUFFIX,mipcache.bdstatic.com,AdBlock\n - DOMAIN-SUFFIX,mipujia.com,AdBlock\n - DOMAIN-SUFFIX,mis.g.mi.com,AdBlock\n - DOMAIN-SUFFIX,miui.hdfdm.com,AdBlock\n - DOMAIN-SUFFIX,miui.hftaili.com,AdBlock\n - DOMAIN-SUFFIX,mivideo.g.mi.com,AdBlock\n - DOMAIN-SUFFIX,mj70.cn,AdBlock\n - DOMAIN-SUFFIX,mjs.csyymp4.com,AdBlock\n - DOMAIN-SUFFIX,mkitgfs.com,AdBlock\n - DOMAIN-SUFFIX,mlb.did.ijinshan.com,AdBlock\n - DOMAIN-SUFFIX,mlgrrqymdsyk.com,AdBlock\n - DOMAIN-SUFFIX,mlnbike.com,AdBlock\n - DOMAIN-SUFFIX,mlog.aipai.com,AdBlock\n - DOMAIN-SUFFIX,mlog.hiido.com,AdBlock\n - DOMAIN-SUFFIX,mlog.m1905.cn,AdBlock\n - DOMAIN-SUFFIX,mlog.search.xiaomi.net,AdBlock\n - DOMAIN-SUFFIX,mlt01.com,AdBlock\n - DOMAIN-SUFFIX,mm.2436.cn,AdBlock\n - DOMAIN-SUFFIX,mm.anqu.com,AdBlock\n - DOMAIN-SUFFIX,mm.jgchq.com,AdBlock\n - DOMAIN-SUFFIX,mm.moquanad.com,AdBlock\n - DOMAIN-SUFFIX,mmcc.yxlady.com,AdBlock\n - DOMAIN-SUFFIX,mmg.aty.cp45.ott.cibntv.net,AdBlock\n - DOMAIN-SUFFIX,mmg.aty.snmsohu.aisee.tv,AdBlock\n - DOMAIN-SUFFIX,mng-ads.com,AdBlock\n - DOMAIN-SUFFIX,mnkan.com,AdBlock\n - DOMAIN-SUFFIX,mnwan.com,AdBlock\n - DOMAIN-SUFFIX,mnxtu.com,AdBlock\n - DOMAIN-SUFFIX,mo.haloapps.cn,AdBlock\n - DOMAIN-SUFFIX,mo.kugou.com,AdBlock\n - DOMAIN-SUFFIX,mo.res.wpscdn.cn,AdBlock\n - DOMAIN-SUFFIX,mo.test.haloapps.com,AdBlock\n - DOMAIN-SUFFIX,moad.cn,AdBlock\n - DOMAIN-SUFFIX,moatads.com,AdBlock\n - DOMAIN-SUFFIX,mob.huimee.net,AdBlock\n - DOMAIN-SUFFIX,mobad.ijinshan.com,AdBlock\n - DOMAIN-SUFFIX,mobadme.jp,AdBlock\n - DOMAIN-SUFFIX,mobclix.com,AdBlock\n - DOMAIN-SUFFIX,mobfox.com,AdBlock\n - DOMAIN-SUFFIX,mobgi.com,AdBlock\n - DOMAIN-SUFFIX,mobilead.kuwo.cn,AdBlock\n - DOMAIN-SUFFIX,mobileads.google.com,AdBlock\n - DOMAIN-SUFFIX,mobileads.msn.com,AdBlock\n - DOMAIN-SUFFIX,mobileapptracking.com,AdBlock\n - DOMAIN-SUFFIX,mobiledissector.com,AdBlock\n - DOMAIN-SUFFIX,mobilelog.kugou.com,AdBlock\n - DOMAIN-SUFFIX,mobile-pubt.ele.me,AdBlock\n - DOMAIN-SUFFIX,mobile-service.segment.com,AdBlock\n - DOMAIN-SUFFIX,mobilityware.com,AdBlock\n - DOMAIN-SUFFIX,mobiorg8.com,AdBlock\n - DOMAIN-SUFFIX,mobisage.cn,AdBlock\n - DOMAIN-SUFFIX,mobvista.com,AdBlock\n - DOMAIN-SUFFIX,mohecm.com,AdBlock\n - DOMAIN-SUFFIX,moka.inte.sogoucdn.com,AdBlock\n - DOMAIN-SUFFIX,mon.xtgreat.com,AdBlock\n - DOMAIN-SUFFIX,monero.how,AdBlock\n - DOMAIN-SUFFIX,money.qz828.com,AdBlock\n - DOMAIN-SUFFIX,monitor.uu.qq.com,AdBlock\n - DOMAIN-SUFFIX,moodoocrv.com.cn,AdBlock\n - DOMAIN-SUFFIX,moogos.com,AdBlock\n - DOMAIN-SUFFIX,mookie1.com,AdBlock\n - DOMAIN-SUFFIX,moons.66bhy.com,AdBlock\n - DOMAIN-SUFFIX,moonwish.com.cn,AdBlock\n - DOMAIN-SUFFIX,mopub.com,AdBlock\n - DOMAIN-SUFFIX,moquanad.com,AdBlock\n - DOMAIN-SUFFIX,moren-1252794300.file.myqcloud.com,AdBlock\n - DOMAIN-SUFFIX,mosa86.com,AdBlock\n - DOMAIN-SUFFIX,mostat.wps.cn,AdBlock\n - DOMAIN-SUFFIX,motohelpr.com,AdBlock\n - DOMAIN-SUFFIX,motu.p4p.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,motu.pagechoice.net,AdBlock\n - DOMAIN-SUFFIX,mou.niu.xunlei.com,AdBlock\n - DOMAIN-SUFFIX,moupdate10332052.wps.cn,AdBlock\n - DOMAIN-SUFFIX,moutaihotel.cn,AdBlock\n - DOMAIN-SUFFIX,movie.miaiche.cn,AdBlock\n - DOMAIN-SUFFIX,mpb1.iteye.com,AdBlock\n - DOMAIN-SUFFIX,mpb2.iteye.com,AdBlock\n - DOMAIN-SUFFIX,mpp.vindicosuite.com,AdBlock\n - DOMAIN-SUFFIX,mpro.baidu.com,AdBlock\n - DOMAIN-SUFFIX,mps.nbcuni.com,AdBlock\n - DOMAIN-SUFFIX,mps.weekslw.com,AdBlock\n - DOMAIN-SUFFIX,mpush.cn,AdBlock\n - DOMAIN-SUFFIX,mpzw.com,AdBlock\n - DOMAIN-SUFFIX,mqq.zgdmsj.cn,AdBlock\n - DOMAIN-SUFFIX,mqqad.cs0309.html5.qq.com,AdBlock\n - DOMAIN-SUFFIX,mqqad.html5.qq.com,AdBlock\n - DOMAIN-SUFFIX,mqqadr.reader.qq.com,AdBlock\n - DOMAIN-SUFFIX,mrelko.com,AdBlock\n - DOMAIN-SUFFIX,mrksys.com,AdBlock\n - DOMAIN-SUFFIX,ms.awqsaged.cn,AdBlock\n - DOMAIN-SUFFIX,ms.cmcm.com,AdBlock\n - DOMAIN-SUFFIX,ms.cnczjy.com,AdBlock\n - DOMAIN-SUFFIX,ms.continuedsys.cn,AdBlock\n - DOMAIN-SUFFIX,ms.ienkdaccessible.cn,AdBlock\n - DOMAIN-SUFFIX,ms.ienkdaccessory.cn,AdBlock\n - DOMAIN-SUFFIX,ms.jyhwt.cn,AdBlock\n - DOMAIN-SUFFIX,ms.myyage.com,AdBlock\n - DOMAIN-SUFFIX,ms.vipstatic.com,AdBlock\n - DOMAIN-SUFFIX,msads.net,AdBlock\n - DOMAIN-SUFFIX,mscimg.com,AdBlock\n - DOMAIN-SUFFIX,msclick2.kuwo.cn,AdBlock\n - DOMAIN-SUFFIX,msg.mobile.kugou.com,AdBlock\n - DOMAIN-SUFFIX,msg.ptqy.gitv.tv,AdBlock\n - DOMAIN-SUFFIX,msg.push.51y5.net,AdBlock\n - DOMAIN-SUFFIX,mshow.fang.com,AdBlock\n - DOMAIN-SUFFIX,msite.baidu.com,AdBlock\n - DOMAIN-SUFFIX,msltzer.cn,AdBlock\n - DOMAIN-SUFFIX,msn.wrating.com,AdBlock\n - DOMAIN-SUFFIX,msnclick.wrating.com,AdBlock\n - DOMAIN-SUFFIX,msphoneclick.kuwo.cn,AdBlock\n - DOMAIN-SUFFIX,mssp.baidu.com,AdBlock\n - DOMAIN-SUFFIX,mstat.zol.com.cn,AdBlock\n - DOMAIN-SUFFIX,mstzym.com,AdBlock\n - DOMAIN-SUFFIX,msypr.com,AdBlock\n - DOMAIN-SUFFIX,mti.35kds.com,AdBlock\n - DOMAIN-SUFFIX,mtj.baidu.com,AdBlock\n - DOMAIN-SUFFIX,mtl.ttsqgs.com,AdBlock\n - DOMAIN-SUFFIX,mtrace.qq.com,AdBlock\n - DOMAIN-SUFFIX,mtty-cdn.mtty.xin,AdBlock\n - DOMAIN-SUFFIX,mtxsk.com,AdBlock\n - DOMAIN-SUFFIX,mubite.cn,AdBlock\n - DOMAIN-SUFFIX,munchkin.marketo.net,AdBlock\n - DOMAIN-SUFFIX,musik-mp3.info,AdBlock\n - DOMAIN-SUFFIX,mvads.kugou.com,AdBlock\n - DOMAIN-SUFFIX,mvip.zhuba8.com,AdBlock\n - DOMAIN-SUFFIX,mwa.xingyimin.com,AdBlock\n - DOMAIN-SUFFIX,mwlucuvbyrff.com,AdBlock\n - DOMAIN-SUFFIX,mxmrt.com,AdBlock\n - DOMAIN-SUFFIX,mxpnl.com,AdBlock\n - DOMAIN-SUFFIX,mxvp-ad-config-prod-1.zenmxapps.com,AdBlock\n - DOMAIN-SUFFIX,mxvp-feature-toggle-prod-1.zenmxapps.com,AdBlock\n - DOMAIN-SUFFIX,my.mobfox.com,AdBlock\n - DOMAIN-SUFFIX,my1fc.m.b5200.net,AdBlock\n - DOMAIN-SUFFIX,my1fimg.m.b5200.net,AdBlock\n - DOMAIN-SUFFIX,myad.toocle.com,AdBlock\n - DOMAIN-SUFFIX,mycleanmymac.com,AdBlock\n - DOMAIN-SUFFIX,mydas.mobi,AdBlock\n - DOMAIN-SUFFIX,mydisplay.ctfile.com,AdBlock\n - DOMAIN-SUFFIX,myjsym.zichenit.com,AdBlock\n - DOMAIN-SUFFIX,mymm.zichenit.com,AdBlock\n - DOMAIN-SUFFIX,mytanwan.com,AdBlock\n - DOMAIN-SUFFIX,mytzdhz.cn,AdBlock\n - DOMAIN-SUFFIX,myycrw.com,AdBlock\n - DOMAIN-SUFFIX,myzk1.com,AdBlock\n - DOMAIN-SUFFIX,myzwqwe12.com,AdBlock\n - DOMAIN-SUFFIX,mzy2014.com,AdBlock\n - DOMAIN-SUFFIX,n.a.mosenni.com,AdBlock\n - DOMAIN-SUFFIX,n.ads3-adnow.com,AdBlock\n - DOMAIN-SUFFIX,n.amoad.com,AdBlock\n - DOMAIN-SUFFIX,n.cosbot.cn,AdBlock\n - DOMAIN-SUFFIX,n.gemini.yahoo.com,AdBlock\n - DOMAIN-SUFFIX,n.ma.social-touch.com,AdBlock\n - DOMAIN-SUFFIX,n.wjr1x.cn,AdBlock\n - DOMAIN-SUFFIX,n.yfi8.com,AdBlock\n - DOMAIN-SUFFIX,n.zqqf0.cn,AdBlock\n - DOMAIN-SUFFIX,na1r.services.adobe.com,AdBlock\n - DOMAIN-SUFFIX,na2m-pr.licenses.adobe.com,AdBlock\n - DOMAIN-SUFFIX,nai.cpxkvc.com,AdBlock\n - DOMAIN-SUFFIX,namedq.com,AdBlock\n - DOMAIN-SUFFIX,namemek.com,AdBlock\n - DOMAIN-SUFFIX,naqigs.com,AdBlock\n - DOMAIN-SUFFIX,nativeapp.toutiao.com,AdBlock\n - DOMAIN-SUFFIX,nav.winasdaq.com,AdBlock\n - DOMAIN-SUFFIX,navi.gd.chinamobile.com,AdBlock\n - DOMAIN-SUFFIX,nbhxgjz.com,AdBlock\n - DOMAIN-SUFFIX,nbjjd.com,AdBlock\n - DOMAIN-SUFFIX,nbzq.net,AdBlock\n - DOMAIN-SUFFIX,nc004x.corp.youdao.com,AdBlock\n - DOMAIN-SUFFIX,nc045x.corp.youdao.com,AdBlock\n - DOMAIN-SUFFIX,ncachear.com,AdBlock\n - DOMAIN-SUFFIX,nch.xnghmc.com,AdBlock\n - DOMAIN-SUFFIX,nchte.com,AdBlock\n - DOMAIN-SUFFIX,nclog.mars.baofeng.net,AdBlock\n - DOMAIN-SUFFIX,nclog.pad.baofeng.net,AdBlock\n - DOMAIN-SUFFIX,ncoyqc.com,AdBlock\n - DOMAIN-SUFFIX,ndtzx.com,AdBlock\n - DOMAIN-SUFFIX,ndy.code.weddingeeos.com,AdBlock\n - DOMAIN-SUFFIX,ne.1rtb.com,AdBlock\n - DOMAIN-SUFFIX,ne9377.com,AdBlock\n - DOMAIN-SUFFIX,neirong.baidu.com,AdBlock\n - DOMAIN-SUFFIX,nend.net,AdBlock\n - DOMAIN-SUFFIX,nest.youwatch.org,AdBlock\n - DOMAIN-SUFFIX,net.rayjump.com,AdBlock\n - DOMAIN-SUFFIX,netko0o.com,AdBlock\n - DOMAIN-SUFFIX,netshelter.net,AdBlock\n - DOMAIN-SUFFIX,netspidermm.indiatimes.com,AdBlock\n - DOMAIN-SUFFIX,network.aufeminin.com,AdBlock\n - DOMAIN-SUFFIX,network.business.com,AdBlock\n - DOMAIN-SUFFIX,network.sofeminine.co.uk,AdBlock\n - DOMAIN-SUFFIX,networkbench.com,AdBlock\n - DOMAIN-SUFFIX,new.ltheanine.cn,AdBlock\n - DOMAIN-SUFFIX,new.yokaunion.com,AdBlock\n - DOMAIN-SUFFIX,new.zhqiu.com,AdBlock\n - DOMAIN-SUFFIX,newapi.com,AdBlock\n - DOMAIN-SUFFIX,newrelic.com,AdBlock\n - DOMAIN-SUFFIX,news.51y5.net,AdBlock\n - DOMAIN-SUFFIX,news.58.com,AdBlock\n - DOMAIN-SUFFIX,news.cxxtv.com,AdBlock\n - DOMAIN-SUFFIX,news.mpush.qq.com,AdBlock\n - DOMAIN-SUFFIX,news.push.126.net,AdBlock\n - DOMAIN-SUFFIX,news.s9377.com,AdBlock\n - DOMAIN-SUFFIX,news.xueyanshan.com,AdBlock\n - DOMAIN-SUFFIX,news-img.51y5.net,AdBlock\n - DOMAIN-SUFFIX,news-l.play.aiseet.atianqi.com,AdBlock\n - DOMAIN-SUFFIX,news-l.play.cp81.ott.cibntv.net,AdBlock\n - DOMAIN-SUFFIX,news-l.play.ott.video.qq.com,AdBlock\n - DOMAIN-SUFFIX,news-log.51y5.net,AdBlock\n - DOMAIN-SUFFIX,newspage.xilu.com,AdBlock\n - DOMAIN-SUFFIX,newspush.sinajs.cn,AdBlock\n - DOMAIN-SUFFIX,newswifiapi.dfshurufa.com,AdBlock\n - DOMAIN-SUFFIX,newton-api.ele.me,AdBlock\n - DOMAIN-SUFFIX,nex.163.com,AdBlock\n - DOMAIN-SUFFIX,nexage.com,AdBlock\n - DOMAIN-SUFFIX,nexstep.zdworks.com,AdBlock\n - DOMAIN-SUFFIX,nextcps.com,AdBlock\n - DOMAIN-SUFFIX,nextlnk9.com,AdBlock\n - DOMAIN-SUFFIX,nexus.ensighten.com,AdBlock\n - DOMAIN-SUFFIX,nfh.cnshef.com,AdBlock\n - DOMAIN-SUFFIX,ngads.go.com,AdBlock\n - DOMAIN-SUFFIX,nicelabel.cc,AdBlock\n - DOMAIN-SUFFIX,ninebox.cn,AdBlock\n - DOMAIN-SUFFIX,ninemsn.imrworldwide.com,AdBlock\n - DOMAIN-SUFFIX,niurenw.com,AdBlock\n - DOMAIN-SUFFIX,niux88.com,AdBlock\n - DOMAIN-SUFFIX,niuxgame77.com,AdBlock\n - DOMAIN-SUFFIX,niwd.zhybw88.com,AdBlock\n - DOMAIN-SUFFIX,njdijiani.com,AdBlock\n - DOMAIN-SUFFIX,njfsk.com,AdBlock\n - DOMAIN-SUFFIX,njmpacc.com,AdBlock\n - DOMAIN-SUFFIX,njq.net,AdBlock\n - DOMAIN-SUFFIX,njs.imagicskin.com,AdBlock\n - DOMAIN-SUFFIX,njs.myyage.com,AdBlock\n - DOMAIN-SUFFIX,njs.reliancevalve.com,AdBlock\n - DOMAIN-SUFFIX,njxczy.com,AdBlock\n - DOMAIN-SUFFIX,nkeo.top,AdBlock\n - DOMAIN-SUFFIX,nlog.baidu.com,AdBlock\n - DOMAIN-SUFFIX,nmbtedu.com,AdBlock\n - DOMAIN-SUFFIX,nmkgs.cn,AdBlock\n - DOMAIN-SUFFIX,nmpcdn.com,AdBlock\n - DOMAIN-SUFFIX,nmqbg.com,AdBlock\n - DOMAIN-SUFFIX,nnedbx.com,AdBlock\n - DOMAIN-SUFFIX,nngft.com,AdBlock\n - DOMAIN-SUFFIX,noberlmall.com,AdBlock\n - DOMAIN-SUFFIX,nongsalei.com,AdBlock\n - DOMAIN-SUFFIX,nop.xpanama.net,AdBlock\n - DOMAIN-SUFFIX,notice.game.xiaomi.com,AdBlock\n - DOMAIN-SUFFIX,notice.uchome.manyou.com,AdBlock\n - DOMAIN-SUFFIX,notifiter.youmi.net,AdBlock\n - DOMAIN-SUFFIX,notify.oupeng.com,AdBlock\n - DOMAIN-SUFFIX,novelsns.html5.qq.com,AdBlock\n - DOMAIN-SUFFIX,nowskip.com,AdBlock\n - DOMAIN-SUFFIX,npdaqy6x1j.me,AdBlock\n - DOMAIN-SUFFIX,nr1234.com,AdBlock\n - DOMAIN-SUFFIX,nryiou.cn,AdBlock\n - DOMAIN-SUFFIX,nsclickvideo.baidu.com,AdBlock\n - DOMAIN-SUFFIX,nsnmiaomu.cn,AdBlock\n - DOMAIN-SUFFIX,nsy.hnzyfs.com,AdBlock\n - DOMAIN-SUFFIX,nt.phpwind.com,AdBlock\n - DOMAIN-SUFFIX,ntalker.com,AdBlock\n - DOMAIN-SUFFIX,nterbx.com,AdBlock\n - DOMAIN-SUFFIX,ntfsformac.cc,AdBlock\n - DOMAIN-SUFFIX,ntfsformac.cn,AdBlock\n - DOMAIN-SUFFIX,nthyn.com,AdBlock\n - DOMAIN-SUFFIX,ntx.quanliyouxi.cn,AdBlock\n - DOMAIN-SUFFIX,nv.souid.com,AdBlock\n - DOMAIN-SUFFIX,nvrentao8.com,AdBlock\n - DOMAIN-SUFFIX,nvshenfan.com,AdBlock\n - DOMAIN-SUFFIX,nwejs.alcryp.com,AdBlock\n - DOMAIN-SUFFIX,nwejs.myzcoffice.com,AdBlock\n - DOMAIN-SUFFIX,nwwap.com,AdBlock\n - DOMAIN-SUFFIX,nxrhs.com,AdBlock\n - DOMAIN-SUFFIX,nxrxt.con,AdBlock\n - DOMAIN-SUFFIX,ny7f6goy.bid,AdBlock\n - DOMAIN-SUFFIX,nylalobghyhirgh.com,AdBlock\n - DOMAIN-SUFFIX,nysita.com,AdBlock\n - DOMAIN-SUFFIX,nzezn.com,AdBlock\n - DOMAIN-SUFFIX,o.08jm.cn,AdBlock\n - DOMAIN-SUFFIX,o.if.qidian.com,AdBlock\n - DOMAIN-SUFFIX,o.minisplat.cn,AdBlock\n - DOMAIN-SUFFIX,o091i.com,AdBlock\n - DOMAIN-SUFFIX,o2o.api.xiaomi.com,AdBlock\n - DOMAIN-SUFFIX,o2omobi.com,AdBlock\n - DOMAIN-SUFFIX,o7xs6runw.bkt.clouddn.com,AdBlock\n - DOMAIN-SUFFIX,oa129.com,AdBlock\n - DOMAIN-SUFFIX,oadz.com,AdBlock\n - DOMAIN-SUFFIX,oa-panther.data.aliyun.com,AdBlock\n - DOMAIN-SUFFIX,oas.autotrader.co.uk,AdBlock\n - DOMAIN-SUFFIX,oas.luxweb.com,AdBlock\n - DOMAIN-SUFFIX,oas.skyscanner.net,AdBlock\n - DOMAIN-SUFFIX,oasc07.citywire.co.uk,AdBlock\n - DOMAIN-SUFFIX,oascentral.abclocal.go.com,AdBlock\n - DOMAIN-SUFFIX,oascentral.chron.com,AdBlock\n - DOMAIN-SUFFIX,oascentral.hosted.ap.org,AdBlock\n - DOMAIN-SUFFIX,oascentral.lycos.com,AdBlock\n - DOMAIN-SUFFIX,oascentral.newsmax.com,AdBlock\n - DOMAIN-SUFFIX,oascentral.sina.com,AdBlock\n - DOMAIN-SUFFIX,oascentral.sina.com.hk,AdBlock\n - DOMAIN-SUFFIX,oask.xulizui6.com,AdBlock\n - DOMAIN-SUFFIX,obeyter.com,AdBlock\n - DOMAIN-SUFFIX,ocbv0.baiyangzs.com,AdBlock\n - DOMAIN-SUFFIX,odc.starwave.com,AdBlock\n - DOMAIN-SUFFIX,odin.goo.mx,AdBlock\n - DOMAIN-SUFFIX,officeme.cn,AdBlock\n - DOMAIN-SUFFIX,offline-adv.oray.com,AdBlock\n - DOMAIN-SUFFIX,oikxlcv.wang,AdBlock\n - DOMAIN-SUFFIX,oimagea2.ydstatic.com,AdBlock\n - DOMAIN-SUFFIX,ojngisbfwwyp.com,AdBlock\n - DOMAIN-SUFFIX,ok.432kkk.com,AdBlock\n - DOMAIN-SUFFIX,ok365.com,AdBlock\n - DOMAIN-SUFFIX,okkkk.com,AdBlock\n - DOMAIN-SUFFIX,okm918.com,AdBlock\n - DOMAIN-SUFFIX,okokw.com,AdBlock\n - DOMAIN-SUFFIX,olcdn.com,AdBlock\n - DOMAIN-SUFFIX,olpv.onlylady.com,AdBlock\n - DOMAIN-SUFFIX,olpvimg.onlylady.com,AdBlock\n - DOMAIN-SUFFIX,olstats.onlylady.com,AdBlock\n - DOMAIN-SUFFIX,omega7o.com,AdBlock\n - DOMAIN-SUFFIX,omg.inte.sogoucdn.com,AdBlock\n - DOMAIN-SUFFIX,omnikool.discovery.com,AdBlock\n - DOMAIN-SUFFIX,omtrdc.net,AdBlock\n - DOMAIN-SUFFIX,on.maxspeedcdn.com,AdBlock\n - DOMAIN-SUFFIX,onclickads.net,AdBlock\n - DOMAIN-SUFFIX,onclicktop.com,AdBlock\n - DOMAIN-SUFFIX,onclkds.com,AdBlock\n - DOMAIN-SUFFIX,one.520319.cn,AdBlock\n - DOMAIN-SUFFIX,onepush.query.yahoo.com,AdBlock\n - DOMAIN-SUFFIX,onesoft.im,AdBlock\n - DOMAIN-SUFFIX,onetad.com,AdBlock\n - DOMAIN-SUFFIX,onetag-sys.com,AdBlock\n - DOMAIN-SUFFIX,onewhee.com,AdBlock\n - DOMAIN-SUFFIX,onlifjj.net,AdBlock\n - DOMAIN-SUFFIX,onlinetips.baofeng5.baofeng.net,AdBlock\n - DOMAIN-SUFFIX,oomyv.com,AdBlock\n - DOMAIN-SUFFIX,ooniu.com,AdBlock\n - DOMAIN-SUFFIX,ooss.oss.aliyuncs.com,AdBlock\n - DOMAIN-SUFFIX,op00w.baiyangzs.com,AdBlock\n - DOMAIN-SUFFIX,open.play.cn,AdBlock\n - DOMAIN-SUFFIX,openapi-news.meizu.com,AdBlock\n - DOMAIN-SUFFIX,openrcv.baidu.com,AdBlock\n - DOMAIN-SUFFIX,openstat.net,AdBlock\n - DOMAIN-SUFFIX,openstorage.ad.cmvideo.cn,AdBlock\n - DOMAIN-SUFFIX,opgirl-tmp.adbxb.cn,AdBlock\n - DOMAIN-SUFFIX,oppo.yidianzixun.com,AdBlock\n - DOMAIN-SUFFIX,optaim.com,AdBlock\n - DOMAIN-SUFFIX,optimix.asia,AdBlock\n - DOMAIN-SUFFIX,optimix.cn,AdBlock\n - DOMAIN-SUFFIX,optimized-by.rubiconproject.com,AdBlock\n - DOMAIN-SUFFIX,optimizelyapis.com,AdBlock\n - DOMAIN-SUFFIX,oq68.com,AdBlock\n - DOMAIN-SUFFIX,orchidscape.net,AdBlock\n - DOMAIN-SUFFIX,oredero.com,AdBlock\n - DOMAIN-SUFFIX,orz.hupu.com,AdBlock\n - DOMAIN-SUFFIX,osc.uranus.sogou.com,AdBlock\n - DOMAIN-SUFFIX,osfota.cdn.aliyun.com,AdBlock\n - DOMAIN-SUFFIX,oss-asq-static.11222.cn,AdBlock\n - DOMAIN-SUFFIX,otf.msn.com,AdBlock\n - DOMAIN-SUFFIX,oth.eve.mdt.qq.com,AdBlock\n - DOMAIN-SUFFIX,oth.str.mdt.qq.com,AdBlock\n - DOMAIN-SUFFIX,oth.update.mdt.qq.com,AdBlock\n - DOMAIN-SUFFIX,otheve.play.aiseet.atianqi.com,AdBlock\n - DOMAIN-SUFFIX,othstr.play.aiseet.atianqi.com,AdBlock\n - DOMAIN-SUFFIX,ou188.com,AdBlock\n - DOMAIN-SUFFIX,output.nend.net,AdBlock\n - DOMAIN-SUFFIX,overture.com,AdBlock\n - DOMAIN-SUFFIX,overturechina.com,AdBlock\n - DOMAIN-SUFFIX,ow.biqugego.com,AdBlock\n - DOMAIN-SUFFIX,ow.s1.shuhuangge.org,AdBlock\n - DOMAIN-SUFFIX,ow.s2.shuhuangge.org,AdBlock\n - DOMAIN-SUFFIX,owin.biqugego.com,AdBlock\n - DOMAIN-SUFFIX,ox.furaffinity.net,AdBlock\n - DOMAIN-SUFFIX,oyzsverimywg.com,AdBlock\n - DOMAIN-SUFFIX,p.7060.la,AdBlock\n - DOMAIN-SUFFIX,p.99mssj.com,AdBlock\n - DOMAIN-SUFFIX,p.abcache.com,AdBlock\n - DOMAIN-SUFFIX,p.bdjiazanmiaomu.com,AdBlock\n - DOMAIN-SUFFIX,p.bjdianyue.com,AdBlock\n - DOMAIN-SUFFIX,p.bnuni.com,AdBlock\n - DOMAIN-SUFFIX,p.clkservice.youdao.com,AdBlock\n - DOMAIN-SUFFIX,p.ecwan77.net,AdBlock\n - DOMAIN-SUFFIX,p.inte.sogou.com,AdBlock\n - DOMAIN-SUFFIX,p.kf3msfm.com,AdBlock\n - DOMAIN-SUFFIX,p.kjwx8.com,AdBlock\n - DOMAIN-SUFFIX,p.kugou.com,AdBlock\n - DOMAIN-SUFFIX,p.m5bn.com,AdBlock\n - DOMAIN-SUFFIX,p.mendoc.cn,AdBlock\n - DOMAIN-SUFFIX,p.niudashu.com,AdBlock\n - DOMAIN-SUFFIX,p.qiailm.com,AdBlock\n - DOMAIN-SUFFIX,p.qijijs.top,AdBlock\n - DOMAIN-SUFFIX,p.raidmedia.com.cn,AdBlock\n - DOMAIN-SUFFIX,p.rfihub.com,AdBlock\n - DOMAIN-SUFFIX,p.saozhu1.top,AdBlock\n - DOMAIN-SUFFIX,p.sdu8cvc.com,AdBlock\n - DOMAIN-SUFFIX,p.shagent.com,AdBlock\n - DOMAIN-SUFFIX,p.skimresources.com,AdBlock\n - DOMAIN-SUFFIX,p.szonline.net,AdBlock\n - DOMAIN-SUFFIX,p.tamenshuo.com,AdBlock\n - DOMAIN-SUFFIX,p.tencentmind.com,AdBlock\n - DOMAIN-SUFFIX,p.twitter.com,AdBlock\n - DOMAIN-SUFFIX,p.vq6nsu.cn,AdBlock\n - DOMAIN-SUFFIX,p.yizuya.com,AdBlock\n - DOMAIN-SUFFIX,p.ynjczy.net,AdBlock\n - DOMAIN-SUFFIX,p0y.cn,AdBlock\n - DOMAIN-SUFFIX,p1.18zhongyao.com,AdBlock\n - DOMAIN-SUFFIX,p1.qinsx.cn,AdBlock\n - DOMAIN-SUFFIX,p2.hyz86.com,AdBlock\n - DOMAIN-SUFFIX,p2.qinsx.cn,AdBlock\n - DOMAIN-SUFFIX,p2.ykauto.cn,AdBlock\n - DOMAIN-SUFFIX,p215223.clksite.com,AdBlock\n - DOMAIN-SUFFIX,p215223.inclk.com,AdBlock\n - DOMAIN-SUFFIX,p215223.mycdn2.co,AdBlock\n - DOMAIN-SUFFIX,p2pmid.baofeng.com,AdBlock\n - DOMAIN-SUFFIX,p3p.sogou.com,AdBlock\n - DOMAIN-SUFFIX,p3p.yahoo.com,AdBlock\n - DOMAIN-SUFFIX,p3tt.com,AdBlock\n - DOMAIN-SUFFIX,p4p.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,p4psearch.china.alibaba.com,AdBlock\n - DOMAIN-SUFFIX,p555.cc,AdBlock\n - DOMAIN-SUFFIX,p8u.hinet.net,AdBlock\n - DOMAIN-SUFFIX,package01.com,AdBlock\n - DOMAIN-SUFFIX,pad.zhywyl.cn,AdBlock\n - DOMAIN-SUFFIX,padsdel2.cdnads.com,AdBlock\n - DOMAIN-SUFFIX,page.acm.dzwww.com,AdBlock\n - DOMAIN-SUFFIX,page.xywy.com,AdBlock\n - DOMAIN-SUFFIX,pagead.google.com,AdBlock\n - DOMAIN-SUFFIX,pagead.l.google.com,AdBlock\n - DOMAIN-SUFFIX,pagead-tpc.l.google.com,AdBlock\n - DOMAIN-SUFFIX,pagechoice.com,AdBlock\n - DOMAIN-SUFFIX,pagechoice.net,AdBlock\n - DOMAIN-SUFFIX,pagechoicemotu.gentags.net,AdBlock\n - DOMAIN-SUFFIX,pages2.marketo.com,AdBlock\n - DOMAIN-SUFFIX,paimgcdn.baidu.com,AdBlock\n - DOMAIN-SUFFIX,painiuimg.com,AdBlock\n - DOMAIN-SUFFIX,palmnews.sina.cn,AdBlock\n - DOMAIN-SUFFIX,panda.kdnet.net,AdBlock\n - DOMAIN-SUFFIX,pangu.cc,AdBlock\n - DOMAIN-SUFFIX,panoramio.com,AdBlock\n - DOMAIN-SUFFIX,papajia55.com,AdBlock\n - DOMAIN-SUFFIX,parking.zunmi.cn,AdBlock\n - DOMAIN-SUFFIX,parser.houyi.baofeng.net,AdBlock\n - DOMAIN-SUFFIX,partner.bargaindomains.com,AdBlock\n - DOMAIN-SUFFIX,partner.catchy.com,AdBlock\n - DOMAIN-SUFFIX,partner.premiumdomains.com,AdBlock\n - DOMAIN-SUFFIX,partner.toutiao.com,AdBlock\n - DOMAIN-SUFFIX,partners.fshealth.com,AdBlock\n - DOMAIN-SUFFIX,partners.keezmovies.com,AdBlock\n - DOMAIN-SUFFIX,partners.optiontide.com,AdBlock\n - DOMAIN-SUFFIX,partners.pornerbros.com,AdBlock\n - DOMAIN-SUFFIX,partners.rochen.com,AdBlock\n - DOMAIN-SUFFIX,partners.sportingbet.com.au,AdBlock\n - DOMAIN-SUFFIX,partners.vouchedfor.co.uk,AdBlock\n - DOMAIN-SUFFIX,partners.xpertmarket.com,AdBlock\n - DOMAIN-SUFFIX,party-nngvitbizn.now.sh,AdBlock\n - DOMAIN-SUFFIX,pasco.cc,AdBlock\n - DOMAIN-SUFFIX,pass1.soogif.com,AdBlock\n - DOMAIN-SUFFIX,pass2.soogif.com,AdBlock\n - DOMAIN-SUFFIX,passwordrecovery.cn,AdBlock\n - DOMAIN-SUFFIX,passwz.com,AdBlock\n - DOMAIN-SUFFIX,pat.farvd.com,AdBlock\n - DOMAIN-SUFFIX,patriot.cs.pp.cn,AdBlock\n - DOMAIN-SUFFIX,pay.holaq.com,AdBlock\n - DOMAIN-SUFFIX,pay.mobile.sina.cn,AdBlock\n - DOMAIN-SUFFIX,pay838.com,AdBlock\n - DOMAIN-SUFFIX,pb.funshion.net.cn,AdBlock\n - DOMAIN-SUFFIX,pb.s3wfg.com,AdBlock\n - DOMAIN-SUFFIX,pb.sogou.com,AdBlock\n - DOMAIN-SUFFIX,pb.sys.pp8.com,AdBlock\n - DOMAIN-SUFFIX,pb.wang502.com,AdBlock\n - DOMAIN-SUFFIX,pb3.pstatp.com,AdBlock\n - DOMAIN-SUFFIX,pbd.sogou.com,AdBlock\n - DOMAIN-SUFFIX,pbs.lenovomm.com,AdBlock\n - DOMAIN-SUFFIX,pc.107788.com,AdBlock\n - DOMAIN-SUFFIX,pc.5151gj.com,AdBlock\n - DOMAIN-SUFFIX,pc.ctsywy.com,AdBlock\n - DOMAIN-SUFFIX,pc.quansj.cn,AdBlock\n - DOMAIN-SUFFIX,pc.videoclick.baidu.com,AdBlock\n - DOMAIN-SUFFIX,pcauto.irs01.com,AdBlock\n - DOMAIN-SUFFIX,pcbrowser.dd.qq.com,AdBlock\n - DOMAIN-SUFFIX,pcfg.wps.cn,AdBlock\n - DOMAIN-SUFFIX,pclog.dftoutiao.com,AdBlock\n - DOMAIN-SUFFIX,pclog.suishenyun.net,AdBlock\n - DOMAIN-SUFFIX,pcmzn.com,AdBlock\n - DOMAIN-SUFFIX,pcsoftwords.dftoutiao.com,AdBlock\n - DOMAIN-SUFFIX,pcxzo.pluto.sogou.com,AdBlock\n - DOMAIN-SUFFIX,pd7-imp.revsci.net,AdBlock\n - DOMAIN-SUFFIX,pdfexpert.cc,AdBlock\n - DOMAIN-SUFFIX,pdl.gionee.com,AdBlock\n - DOMAIN-SUFFIX,pdsjycm.com,AdBlock\n - DOMAIN-SUFFIX,pear.dleke.com,AdBlock\n - DOMAIN-SUFFIX,pedailyu.com,AdBlock\n - DOMAIN-SUFFIX,pee.cn,AdBlock\n - DOMAIN-SUFFIX,pegasus.cmcm.com,AdBlock\n - DOMAIN-SUFFIX,pei-ads.playboy.com,AdBlock\n - DOMAIN-SUFFIX,pf.h5game.cn,AdBlock\n - DOMAIN-SUFFIX,pf.pchome.net,AdBlock\n - DOMAIN-SUFFIX,pf-2.pchome.net,AdBlock\n - DOMAIN-SUFFIX,pfp.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,pfpip.sina.com,AdBlock\n - DOMAIN-SUFFIX,pgdt.gtimg.cn,AdBlock\n - DOMAIN-SUFFIX,pgdt.ugdtimg.com,AdBlock\n - DOMAIN-SUFFIX,photo.dhford.cn,AdBlock\n - DOMAIN-SUFFIX,photo.lyghjzs.cn,AdBlock\n - DOMAIN-SUFFIX,photo.qianerbai.cn,AdBlock\n - DOMAIN-SUFFIX,photo.shyexiang.cn,AdBlock\n - DOMAIN-SUFFIX,photo.welldex.cn,AdBlock\n - DOMAIN-SUFFIX,photo.xunhuaji.cn,AdBlock\n - DOMAIN-SUFFIX,photo.zhanhevr.cn,AdBlock\n - DOMAIN-SUFFIX,phpad.cqnews.net,AdBlock\n - DOMAIN-SUFFIX,pic.0597kk.com,AdBlock\n - DOMAIN-SUFFIX,pic.14bobo.com,AdBlock\n - DOMAIN-SUFFIX,pic.2u.com.cn,AdBlock\n - DOMAIN-SUFFIX,pic.adver.com.tw,AdBlock\n - DOMAIN-SUFFIX,pic.aihaogou.com.cn,AdBlock\n - DOMAIN-SUFFIX,pic.by175.com,AdBlock\n - DOMAIN-SUFFIX,pic.casee.cn,AdBlock\n - DOMAIN-SUFFIX,pic.cnmo-img.com.cn,AdBlock\n - DOMAIN-SUFFIX,pic.dotmore.com.tw,AdBlock\n - DOMAIN-SUFFIX,pic.ea3w.com,AdBlock\n - DOMAIN-SUFFIX,pic.eduancm.com,AdBlock\n - DOMAIN-SUFFIX,pic.fengniao.com,AdBlock\n - DOMAIN-SUFFIX,pic.haowj.com.cn,AdBlock\n - DOMAIN-SUFFIX,pic.jdbbs.com,AdBlock\n - DOMAIN-SUFFIX,pic.jd-bbs.com,AdBlock\n - DOMAIN-SUFFIX,pic.jdunion.com,AdBlock\n - DOMAIN-SUFFIX,pic.moad.cn,AdBlock\n - DOMAIN-SUFFIX,pic.neiyicun.net,AdBlock\n - DOMAIN-SUFFIX,pic.new400.cn,AdBlock\n - DOMAIN-SUFFIX,pic.pic-img.com,AdBlock\n - DOMAIN-SUFFIX,pic.punchbox.org,AdBlock\n - DOMAIN-SUFFIX,pic.pxstda.com,AdBlock\n - DOMAIN-SUFFIX,pic.usingde.com,AdBlock\n - DOMAIN-SUFFIX,pic.zol-img.com.cn,AdBlock\n - DOMAIN-SUFFIX,pic1.59wd.com,AdBlock\n - DOMAIN-SUFFIX,pic1.onetad.com,AdBlock\n - DOMAIN-SUFFIX,pic183025.images9999.com,AdBlock\n - DOMAIN-SUFFIX,pic2.onetad.com,AdBlock\n - DOMAIN-SUFFIX,pic2016.5442.com,AdBlock\n - DOMAIN-SUFFIX,pic2016.ytqmx.com,AdBlock\n - DOMAIN-SUFFIX,pic3.onetad.com,AdBlock\n - DOMAIN-SUFFIX,pic494036.images9999.com,AdBlock\n - DOMAIN-SUFFIX,pic8.onetad.com,AdBlock\n - DOMAIN-SUFFIX,pic837013.images9999.com,AdBlock\n - DOMAIN-SUFFIX,picsinfog.com,AdBlock\n - DOMAIN-SUFFIX,picture.duokan.com,AdBlock\n - DOMAIN-SUFFIX,picturesquefilms.net,AdBlock\n - DOMAIN-SUFFIX,pikacn.com,AdBlock\n - DOMAIN-SUFFIX,pimg1.126.net,AdBlock\n - DOMAIN-SUFFIX,ping.acc.sogou.com,AdBlock\n - DOMAIN-SUFFIX,ping.chartbeat.net,AdBlock\n - DOMAIN-SUFFIX,ping.pinyin.sogou.com,AdBlock\n - DOMAIN-SUFFIX,ping.weiduofan.com,AdBlock\n - DOMAIN-SUFFIX,pingbi.diudou.com,AdBlock\n - DOMAIN-SUFFIX,pingdom.net,AdBlock\n - DOMAIN-SUFFIX,pingma.qq.com,AdBlock\n - DOMAIN-SUFFIX,pingshetrip.com,AdBlock\n - DOMAIN-SUFFIX,pintour.com,AdBlock\n - DOMAIN-SUFFIX,pinzhitmall.com,AdBlock\n - DOMAIN-SUFFIX,pix.impdesk.com,AdBlock\n - DOMAIN-SUFFIX,pix.tagcdn.com,AdBlock\n - DOMAIN-SUFFIX,pix04.revsci.net,AdBlock\n - DOMAIN-SUFFIX,pixel.adsafeprotected.com,AdBlock\n - DOMAIN-SUFFIX,pixel.mathtag.com,AdBlock\n - DOMAIN-SUFFIX,pixel.quantserve.com,AdBlock\n - DOMAIN-SUFFIX,pixel.rubiconproject.com,AdBlock\n - DOMAIN-SUFFIX,pixel.tapad.com,AdBlock\n - DOMAIN-SUFFIX,pixel.vihub.ru,AdBlock\n - DOMAIN-SUFFIX,pixel.wp.com,AdBlock\n - DOMAIN-SUFFIX,pixel-hk.pixelinteractivemedia.com,AdBlock\n - DOMAIN-SUFFIX,pixels.asia,AdBlock\n - DOMAIN-SUFFIX,pixfuture.net,AdBlock\n - DOMAIN-SUFFIX,pj3456.com,AdBlock\n - DOMAIN-SUFFIX,pj39330.com,AdBlock\n - DOMAIN-SUFFIX,pj50.com,AdBlock\n - DOMAIN-SUFFIX,pj5189.com,AdBlock\n - DOMAIN-SUFFIX,pj550077.com,AdBlock\n - DOMAIN-SUFFIX,pjbjzf.com,AdBlock\n - DOMAIN-SUFFIX,pjogndc8ixoidna.360doc.cn,AdBlock\n - DOMAIN-SUFFIX,pjtymy.cn,AdBlock\n - DOMAIN-SUFFIX,pjyu.golden1.sogou.com,AdBlock\n - DOMAIN-SUFFIX,pk840.com,AdBlock\n - DOMAIN-SUFFIX,p-l.play.aiseet.atianqi.com,AdBlock\n - DOMAIN-SUFFIX,pl108258.puserving.com,AdBlock\n - DOMAIN-SUFFIX,pl14369502.puserving.com,AdBlock\n - DOMAIN-SUFFIX,platform.wondershare.com,AdBlock\n - DOMAIN-SUFFIX,playad.xjmg.com,AdBlock\n - DOMAIN-SUFFIX,player.1800coupon.com,AdBlock\n - DOMAIN-SUFFIX,player.1stcreditrepairs.com,AdBlock\n - DOMAIN-SUFFIX,player.800directories.com,AdBlock\n - DOMAIN-SUFFIX,player.accoona.com,AdBlock\n - DOMAIN-SUFFIX,player.alloutwedding.com,AdBlock\n - DOMAIN-SUFFIX,player.insuranceandhealth.com,AdBlock\n - DOMAIN-SUFFIX,playinfo.gomlab.com,AdBlock\n - DOMAIN-SUFFIX,plista.com,AdBlock\n - DOMAIN-SUFFIX,plmkolp.m.58xs.tw,AdBlock\n - DOMAIN-SUFFIX,plt.data.pplive.com,AdBlock\n - DOMAIN-SUFFIX,plwan.com,AdBlock\n - DOMAIN-SUFFIX,plz.jandan.net,AdBlock\n - DOMAIN-SUFFIX,pm.sdaiv.com,AdBlock\n - DOMAIN-SUFFIX,pmir.3g.qq.com,AdBlock\n - DOMAIN-SUFFIX,pmm.people.com.cn,AdBlock\n - DOMAIN-SUFFIX,pmptrack-autohome.gentags.net,AdBlock\n - DOMAIN-SUFFIX,pmptrack-letv.gentags.net,AdBlock\n - DOMAIN-SUFFIX,pmptrack-yidianzixunxm.gentags.net,AdBlock\n - DOMAIN-SUFFIX,pmptrack-youku.gentags.net,AdBlock\n - DOMAIN-SUFFIX,png.lu.sogoucdn.com,AdBlock\n - DOMAIN-SUFFIX,pnhfc.com,AdBlock\n - DOMAIN-SUFFIX,pofang.com,AdBlock\n - DOMAIN-SUFFIX,polkoa.com,AdBlock\n - DOMAIN-SUFFIX,pomhz.com,AdBlock\n - DOMAIN-SUFFIX,pop.91mangrandi.com,AdBlock\n - DOMAIN-SUFFIX,pop.code.mytanwan.com,AdBlock\n - DOMAIN-SUFFIX,pop.code.poyang.cn,AdBlock\n - DOMAIN-SUFFIX,pop.sjk.ijinshan.com,AdBlock\n - DOMAIN-SUFFIX,popads.net,AdBlock\n - DOMAIN-SUFFIX,popme.163.com,AdBlock\n - DOMAIN-SUFFIX,poppyta.com,AdBlock\n - DOMAIN-SUFFIX,popup.jointreport-switch.com,AdBlock\n - DOMAIN-SUFFIX,popup.msn.com,AdBlock\n - DOMAIN-SUFFIX,popupad.cn,AdBlock\n - DOMAIN-SUFFIX,post.ra.icast.cn,AdBlock\n - DOMAIN-SUFFIX,poster.weather.com.cn,AdBlock\n - DOMAIN-SUFFIX,powergg.top,AdBlock\n - DOMAIN-SUFFIX,poyang.com,AdBlock\n - DOMAIN-SUFFIX,pp.sxjkc.cn,AdBlock\n - DOMAIN-SUFFIX,pp2.dhzw.org,AdBlock\n - DOMAIN-SUFFIX,pp9899.com,AdBlock\n - DOMAIN-SUFFIX,ppjia55.com,AdBlock\n - DOMAIN-SUFFIX,ppoi.org,AdBlock\n - DOMAIN-SUFFIX,ppurifier.game.xiaomi.com,AdBlock\n - DOMAIN-SUFFIX,ppx.hgo7r.cn,AdBlock\n - DOMAIN-SUFFIX,pr.atwola.com,AdBlock\n - DOMAIN-SUFFIX,pr.ybp.yahoo.com,AdBlock\n - DOMAIN-SUFFIX,pr00001.com,AdBlock\n - DOMAIN-SUFFIX,practivate.adobe.com,AdBlock\n - DOMAIN-SUFFIX,pr-bh.ybp.yahoo.com,AdBlock\n - DOMAIN-SUFFIX,prc.rjje4.com,AdBlock\n - DOMAIN-SUFFIX,prcappzone.intel.com,AdBlock\n - DOMAIN-SUFFIX,pre.api.tw06.xlmc.sandai.net,AdBlock\n - DOMAIN-SUFFIX,pre.ra.icast.cn,AdBlock\n - DOMAIN-SUFFIX,prerollads.ign.com,AdBlock\n - DOMAIN-SUFFIX,priceinfo.comuv.com,AdBlock\n - DOMAIN-SUFFIX,pro.cn,AdBlock\n - DOMAIN-SUFFIX,pro.heiguang.com,AdBlock\n - DOMAIN-SUFFIX,pro.iweihai.cn,AdBlock\n - DOMAIN-SUFFIX,probes.cedexis.com,AdBlock\n - DOMAIN-SUFFIX,profile.ssp.rambler.ru,AdBlock\n - DOMAIN-SUFFIX,projectwonderful.com,AdBlock\n - DOMAIN-SUFFIX,prom.gome.com.cn,AdBlock\n - DOMAIN-SUFFIX,promo.fileforum.com,AdBlock\n - DOMAIN-SUFFIX,promos.fling.com,AdBlock\n - DOMAIN-SUFFIX,promote.biz.weibo.cn,AdBlock\n - DOMAIN-SUFFIX,promote.caixin.com,AdBlock\n - DOMAIN-SUFFIX,promote.pair.com,AdBlock\n - DOMAIN-SUFFIX,promotion.aliyun.com,AdBlock\n - DOMAIN-SUFFIX,promotion.gomlab.com,AdBlock\n - DOMAIN-SUFFIX,promotions.iasbet.com,AdBlock\n - DOMAIN-SUFFIX,propellerads.com,AdBlock\n - DOMAIN-SUFFIX,prophet.heise.de,AdBlock\n - DOMAIN-SUFFIX,proton.flurry.com,AdBlock\n - DOMAIN-SUFFIX,proxy.sec.miui.com,AdBlock\n - DOMAIN-SUFFIX,prw.lenovomm.com,AdBlock\n - DOMAIN-SUFFIX,ps.3fenge.com,AdBlock\n - DOMAIN-SUFFIX,psb.lenovomm.com,AdBlock\n - DOMAIN-SUFFIX,psfq.gou.sogou.com,AdBlock\n - DOMAIN-SUFFIX,psma02.com,AdBlock\n - DOMAIN-SUFFIX,ptdrw.com,AdBlock\n - DOMAIN-SUFFIX,ptkhy.com,AdBlock\n - DOMAIN-SUFFIX,ptw.la,AdBlock\n - DOMAIN-SUFFIX,pub.betclick.com,AdBlock\n - DOMAIN-SUFFIX,pub.chinadailyasia.com,AdBlock\n - DOMAIN-SUFFIX,pub.funshion.com,AdBlock\n - DOMAIN-SUFFIX,pub.mop.com,AdBlock\n - DOMAIN-SUFFIX,pub1.cope.es,AdBlock\n - DOMAIN-SUFFIX,pubbirdf.com,AdBlock\n - DOMAIN-SUFFIX,public6.com,AdBlock\n - DOMAIN-SUFFIX,publicidad.net,AdBlock\n - DOMAIN-SUFFIX,publicidad.tv,AdBlock\n - DOMAIN-SUFFIX,publish.ad.youth.cn,AdBlock\n - DOMAIN-SUFFIX,pubmatic.com,AdBlock\n - DOMAIN-SUFFIX,pubnative.net,AdBlock\n - DOMAIN-SUFFIX,pubnub.com,AdBlock\n - DOMAIN-SUFFIX,pubs.hiddennetwork.com,AdBlock\n - DOMAIN-SUFFIX,puds.test.uae.uc.cn,AdBlock\n - DOMAIN-SUFFIX,puds.ucweb.com,AdBlock\n - DOMAIN-SUFFIX,pull.push.sogou.com,AdBlock\n - DOMAIN-SUFFIX,punchbox.org,AdBlock\n - DOMAIN-SUFFIX,punuomisi.cn,AdBlock\n - DOMAIN-SUFFIX,pups.bdimg.com,AdBlock\n - DOMAIN-SUFFIX,pupu.xnhh120.com,AdBlock\n - DOMAIN-SUFFIX,push.126.net,AdBlock\n - DOMAIN-SUFFIX,push.5z5zw.com,AdBlock\n - DOMAIN-SUFFIX,push.air-matters.com,AdBlock\n - DOMAIN-SUFFIX,push.com2us.net,AdBlock\n - DOMAIN-SUFFIX,push.feng.com,AdBlock\n - DOMAIN-SUFFIX,push.mobile.kugou.com,AdBlock\n - DOMAIN-SUFFIX,push.res.meizu.com,AdBlock\n - DOMAIN-SUFFIX,push.wandoujia.com,AdBlock\n - DOMAIN-SUFFIX,push.wapx.cn,AdBlock\n - DOMAIN-SUFFIX,push.yuedu.163.com,AdBlock\n - DOMAIN-SUFFIX,push.zdworks.com,AdBlock\n - DOMAIN-SUFFIX,push.zhangyue.com,AdBlock\n - DOMAIN-SUFFIX,push.zhanzhang.baidu.com,AdBlock\n - DOMAIN-SUFFIX,push-android.myzaker.com,AdBlock\n - DOMAIN-SUFFIX,pushapi.lenovomm.com,AdBlock\n - DOMAIN-SUFFIX,push-dc.51y5.net,AdBlock\n - DOMAIN-SUFFIX,pv.anzhi.com,AdBlock\n - DOMAIN-SUFFIX,pv.cheshi.com,AdBlock\n - DOMAIN-SUFFIX,pv.enet.com.cn,AdBlock\n - DOMAIN-SUFFIX,pv.focus.cn,AdBlock\n - DOMAIN-SUFFIX,pv.ra.icast.cn,AdBlock\n - DOMAIN-SUFFIX,pv.sogou.com,AdBlock\n - DOMAIN-SUFFIX,pv.xcar.com.cn,AdBlock\n - DOMAIN-SUFFIX,pv.zdnet.com.cn,AdBlock\n - DOMAIN-SUFFIX,pv.zol.com.cn,AdBlock\n - DOMAIN-SUFFIX,pvc.zol.com.cn,AdBlock\n - DOMAIN-SUFFIX,pvdata.ku6.com,AdBlock\n - DOMAIN-SUFFIX,pvlog.hd.baofeng.com,AdBlock\n - DOMAIN-SUFFIX,pvlog.moviebox.baofeng.net,AdBlock\n - DOMAIN-SUFFIX,pvm.zol.com.cn,AdBlock\n - DOMAIN-SUFFIX,pvmsite.zol.com.cn,AdBlock\n - DOMAIN-SUFFIX,pvsite.zol.com.cn,AdBlock\n - DOMAIN-SUFFIX,pvstat.html5.qq.com,AdBlock\n - DOMAIN-SUFFIX,pvtest.zol.com.cn,AdBlock\n - DOMAIN-SUFFIX,pwj.biqugezw.com,AdBlock\n - DOMAIN-SUFFIX,px.adhigh.net,AdBlock\n - DOMAIN-SUFFIX,px.media-serving.com,AdBlock\n - DOMAIN-SUFFIX,px.moatads.com,AdBlock\n - DOMAIN-SUFFIX,px.owneriq.net,AdBlock\n - DOMAIN-SUFFIX,px.powerlinks.com,AdBlock\n - DOMAIN-SUFFIX,px.steelhousemedia.com,AdBlock\n - DOMAIN-SUFFIX,pxene.com,AdBlock\n - DOMAIN-SUFFIX,pxl.connexity.net,AdBlock\n - DOMAIN-SUFFIX,py.qlogo.cn,AdBlock\n - DOMAIN-SUFFIX,py.wikigifth.com,AdBlock\n - DOMAIN-SUFFIX,py2.qlogo.cn,AdBlock\n - DOMAIN-SUFFIX,pyerc.com,AdBlock\n - DOMAIN-SUFFIX,pyzkk.com,AdBlock\n - DOMAIN-SUFFIX,q.ox11.com,AdBlock\n - DOMAIN-SUFFIX,q.s.cr-nielsen.com,AdBlock\n - DOMAIN-SUFFIX,q1scv.vov0.com,AdBlock\n - DOMAIN-SUFFIX,q6rwa.eschangchi.com,AdBlock\n - DOMAIN-SUFFIX,qbyy010.com,AdBlock\n - DOMAIN-SUFFIX,qchannel01.cn,AdBlock\n - DOMAIN-SUFFIX,qchannel02.cn,AdBlock\n - DOMAIN-SUFFIX,qchannel03.cn,AdBlock\n - DOMAIN-SUFFIX,qchannel04.cn,AdBlock\n - DOMAIN-SUFFIX,qcjslm.com,AdBlock\n - DOMAIN-SUFFIX,qcl777.com,AdBlock\n - DOMAIN-SUFFIX,qd.dhzw.org,AdBlock\n - DOMAIN-SUFFIX,qd.js.sanjiangge.com,AdBlock\n - DOMAIN-SUFFIX,qd.moutaihotel.cn,AdBlock\n - DOMAIN-SUFFIX,qd.wanjuanba.com,AdBlock\n - DOMAIN-SUFFIX,qd.x4399.com,AdBlock\n - DOMAIN-SUFFIX,qdchunyu.com,AdBlock\n - DOMAIN-SUFFIX,qeoa.hawbfa.com,AdBlock\n - DOMAIN-SUFFIX,qgss8.com,AdBlock\n - DOMAIN-SUFFIX,qhaif.com,AdBlock\n - DOMAIN-SUFFIX,qhl.bealge.sogou.com,AdBlock\n - DOMAIN-SUFFIX,qiailm.com,AdBlock\n - DOMAIN-SUFFIX,qianclick.baidu.com,AdBlock\n - DOMAIN-SUFFIX,qiaopiguniang.com,AdBlock\n - DOMAIN-SUFFIX,qichexin.com,AdBlock\n - DOMAIN-SUFFIX,qihaoqu.com,AdBlock\n - DOMAIN-SUFFIX,qinchugudao.com,AdBlock\n - DOMAIN-SUFFIX,qingqu.la,AdBlock\n - DOMAIN-SUFFIX,qiqipower.com,AdBlock\n - DOMAIN-SUFFIX,qiqivv.com,AdBlock\n - DOMAIN-SUFFIX,qiqiww.com,AdBlock\n - DOMAIN-SUFFIX,qiqiyii.com,AdBlock\n - DOMAIN-SUFFIX,qiye11.ejunshi.net,AdBlock\n - DOMAIN-SUFFIX,qiyem.ejunshi.com,AdBlock\n - DOMAIN-SUFFIX,qiyezs.ejunshi.com,AdBlock\n - DOMAIN-SUFFIX,qiyou.com,AdBlock\n - DOMAIN-SUFFIX,qjfcdn1220.0101122.com,AdBlock\n - DOMAIN-SUFFIX,qjjtc.com,AdBlock\n - DOMAIN-SUFFIX,qlisv.siemens6es7.com,AdBlock\n - DOMAIN-SUFFIX,qlmho.renhengshangmao.com,AdBlock\n - DOMAIN-SUFFIX,qloer.com,AdBlock\n - DOMAIN-SUFFIX,qlonglong.com,AdBlock\n - DOMAIN-SUFFIX,qmkdy.com,AdBlock\n - DOMAIN-SUFFIX,qoiusky.com,AdBlock\n - DOMAIN-SUFFIX,qooic.com,AdBlock\n - DOMAIN-SUFFIX,qp.yunanfuwuqi.com,AdBlock\n - DOMAIN-SUFFIX,qq.guansenff.cn,AdBlock\n - DOMAIN-SUFFIX,qq.irs01.com,AdBlock\n - DOMAIN-SUFFIX,qq.tapiche.cn,AdBlock\n - DOMAIN-SUFFIX,qq2.co,AdBlock\n - DOMAIN-SUFFIX,qq61.com,AdBlock\n - DOMAIN-SUFFIX,qqhuhu.com,AdBlock\n - DOMAIN-SUFFIX,qqm98.com,AdBlock\n - DOMAIN-SUFFIX,qqshow2-item.qq.com,AdBlock\n - DOMAIN-SUFFIX,qqx.cqqytgpt.com,AdBlock\n - DOMAIN-SUFFIX,qqzu.com,AdBlock\n - DOMAIN-SUFFIX,qsbz2011.com,AdBlock\n - DOMAIN-SUFFIX,qshxc.com,AdBlock\n - DOMAIN-SUFFIX,qt.biqugezw.com,AdBlock\n - DOMAIN-SUFFIX,qt002x.corp.youdao.com,AdBlock\n - DOMAIN-SUFFIX,qtmojo.cn,AdBlock\n - DOMAIN-SUFFIX,qtmojo.com,AdBlock\n - DOMAIN-SUFFIX,quanliyouxi.cn,AdBlock\n - DOMAIN-SUFFIX,quansj.cn,AdBlock\n - DOMAIN-SUFFIX,quantcount.com,AdBlock\n - DOMAIN-SUFFIX,quantserve.com,AdBlock\n - DOMAIN-SUFFIX,qucaigg.com,AdBlock\n - DOMAIN-SUFFIX,queene.cn,AdBlock\n - DOMAIN-SUFFIX,questionmarket.com,AdBlock\n - DOMAIN-SUFFIX,qujishu.com,AdBlock\n - DOMAIN-SUFFIX,qumi.com,AdBlock\n - DOMAIN-SUFFIX,qupinhj.com,AdBlock\n - DOMAIN-SUFFIX,qutaobi.com,AdBlock\n - DOMAIN-SUFFIX,quw18.com,AdBlock\n - DOMAIN-SUFFIX,quyaoya.com,AdBlock\n - DOMAIN-SUFFIX,qweqwe.mctvhp.cn,AdBlock\n - DOMAIN-SUFFIX,qxjdlf.com,AdBlock\n - DOMAIN-SUFFIX,qxm.pluto.sogou.com,AdBlock\n - DOMAIN-SUFFIX,qxxys.com,AdBlock\n - DOMAIN-SUFFIX,qyctj.com,AdBlock\n - DOMAIN-SUFFIX,qytyf.com,AdBlock\n - DOMAIN-SUFFIX,qzdag.com,AdBlock\n - DOMAIN-SUFFIX,qzdfc.com,AdBlock\n - DOMAIN-SUFFIX,qzgjprj.com,AdBlock\n - DOMAIN-SUFFIX,qzkxt.com,AdBlock\n - DOMAIN-SUFFIX,r.0.0.0.0.cn,AdBlock\n - DOMAIN-SUFFIX,r.254a.com,AdBlock\n - DOMAIN-SUFFIX,r.5207470.com,AdBlock\n - DOMAIN-SUFFIX,r.browser.miui.com,AdBlock\n - DOMAIN-SUFFIX,r.bxb.oupeng.com,AdBlock\n - DOMAIN-SUFFIX,r.dmp.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,r.mail.163.com,AdBlock\n - DOMAIN-SUFFIX,r.msn.com,AdBlock\n - DOMAIN-SUFFIX,r.myadx.net,AdBlock\n - DOMAIN-SUFFIX,r.ow.0.0.0.0.cn,AdBlock\n - DOMAIN-SUFFIX,r.pixgold.com,AdBlock\n - DOMAIN-SUFFIX,r.radikal.ru,AdBlock\n - DOMAIN-SUFFIX,r.xcycm.com,AdBlock\n - DOMAIN-SUFFIX,r.youmi.net,AdBlock\n - DOMAIN-SUFFIX,r.zlongad.com,AdBlock\n - DOMAIN-SUFFIX,r8nu86wg.me,AdBlock\n - DOMAIN-SUFFIX,ra.gtimg.com,AdBlock\n - DOMAIN-SUFFIX,rabbit.meitustat.com,AdBlock\n - DOMAIN-SUFFIX,rabbit.tg.meitu.com,AdBlock\n - DOMAIN-SUFFIX,rack.bauermedia.co.uk,AdBlock\n - DOMAIN-SUFFIX,rad.live.com,AdBlock\n - DOMAIN-SUFFIX,rad.microsoft.com,AdBlock\n - DOMAIN-SUFFIX,rad.msn.com,AdBlock\n - DOMAIN-SUFFIX,rad.reporo.net,AdBlock\n - DOMAIN-SUFFIX,radar.cedexis.com,AdBlock\n - DOMAIN-SUFFIX,raeqqe.cn,AdBlock\n - DOMAIN-SUFFIX,rank.hit.china.com,AdBlock\n - DOMAIN-SUFFIX,rannabio.com,AdBlock\n - DOMAIN-SUFFIX,ratings.lycos.com,AdBlock\n - DOMAIN-SUFFIX,raw.okwan.cn,AdBlock\n - DOMAIN-SUFFIX,rayjump.com,AdBlock\n - DOMAIN-SUFFIX,rbp.emea.mxptint.net,AdBlock\n - DOMAIN-SUFFIX,rbp.mxptint.net,AdBlock\n - DOMAIN-SUFFIX,rbs.haiyunx.com,AdBlock\n - DOMAIN-SUFFIX,rbywg.com,AdBlock\n - DOMAIN-SUFFIX,rc.fthcz.com,AdBlock\n - DOMAIN-SUFFIX,rc.haodongkeji.cn,AdBlock\n - DOMAIN-SUFFIX,rc.mgwcn.com,AdBlock\n - DOMAIN-SUFFIX,rc.xmcmn.com,AdBlock\n - DOMAIN-SUFFIX,rc2waycm-atl.netmng.com,AdBlock\n - DOMAIN-SUFFIX,rc-au.imrworldwide.com,AdBlock\n - DOMAIN-SUFFIX,rcmd.pop.ijinshan.com,AdBlock\n - DOMAIN-SUFFIX,rcp.c.appier.net,AdBlock\n - DOMAIN-SUFFIX,rcv.iclicash.com,AdBlock\n - DOMAIN-SUFFIX,rcv.jesgoo.com,AdBlock\n - DOMAIN-SUFFIX,rcv.mobad.ijinshan.com,AdBlock\n - DOMAIN-SUFFIX,rcv.moogos.com,AdBlock\n - DOMAIN-SUFFIX,rcv.union-wifi.com,AdBlock\n - DOMAIN-SUFFIX,rcyy3.kaopuwangjz.com,AdBlock\n - DOMAIN-SUFFIX,rd.ane.yahoo.co.jp,AdBlock\n - DOMAIN-SUFFIX,rd.e.sogou.com,AdBlock\n - DOMAIN-SUFFIX,rdiqt.cn,AdBlock\n - DOMAIN-SUFFIX,rdtuijian.com,AdBlock\n - DOMAIN-SUFFIX,re.m.taobao.com,AdBlock\n - DOMAIN-SUFFIX,re.taobao.com,AdBlock\n - DOMAIN-SUFFIX,re.taotaosou.com,AdBlock\n - DOMAIN-SUFFIX,reachmax.cn,AdBlock\n - DOMAIN-SUFFIX,reader.browser.miui.com,AdBlock\n - DOMAIN-SUFFIX,reader.meizu.com,AdBlock\n - DOMAIN-SUFFIX,reader.res.meizu.com,AdBlock\n - DOMAIN-SUFFIX,realtime.monitor.ppweb.com.cn,AdBlock\n - DOMAIN-SUFFIX,rec.g.163.com,AdBlock\n - DOMAIN-SUFFIX,rec.moviebox.baofeng.net,AdBlock\n - DOMAIN-SUFFIX,recreativ.ru,AdBlock\n - DOMAIN-SUFFIX,recv-vd.gridsumdissector.cn,AdBlock\n - DOMAIN-SUFFIX,recv-vd.gridsumdissector.com,AdBlock\n - DOMAIN-SUFFIX,recv-wd.gridsumdissector.com,AdBlock\n - DOMAIN-SUFFIX,red.bayimg.net,AdBlock\n - DOMAIN-SUFFIX,redirect.simba.taobao.com,AdBlock\n - DOMAIN-SUFFIX,redpaper-10006092.cos.myqcloud.com,AdBlock\n - DOMAIN-SUFFIX,redvase.bravenet.com,AdBlock\n - DOMAIN-SUFFIX,referrer.disqus.com,AdBlock\n - DOMAIN-SUFFIX,relap.io,AdBlock\n - DOMAIN-SUFFIX,release.baidu.com,AdBlock\n - DOMAIN-SUFFIX,reliancevalve.com,AdBlock\n - DOMAIN-SUFFIX,remote88.com,AdBlock\n - DOMAIN-SUFFIX,remotedu.cn,AdBlock\n - DOMAIN-SUFFIX,rem-track.bild.de,AdBlock\n - DOMAIN-SUFFIX,rencai56.com,AdBlock\n - DOMAIN-SUFFIX,renren2.maoyun.tv,AdBlock\n - DOMAIN-SUFFIX,req.startappservice.com,AdBlock\n - DOMAIN-SUFFIX,res.cocounion.com,AdBlock\n - DOMAIN-SUFFIX,res.dxpmedia.com,AdBlock\n - DOMAIN-SUFFIX,res.icast.cn,AdBlock\n - DOMAIN-SUFFIX,res.ipingke.com,AdBlock\n - DOMAIN-SUFFIX,res.qhupdate.com,AdBlock\n - DOMAIN-SUFFIX,res3.feedsportal.com,AdBlock\n - DOMAIN-SUFFIX,rescn.u3.ucweb.com,AdBlock\n - DOMAIN-SUFFIX,resetgey.com,AdBlock\n - DOMAIN-SUFFIX,res-ga.smzdm.com,AdBlock\n - DOMAIN-SUFFIX,resolver.gslb.mi-idc.com,AdBlock\n - DOMAIN-SUFFIX,resolver.msg.xiaomi.net,AdBlock\n - DOMAIN-SUFFIX,resource.baomihua.com,AdBlock\n - DOMAIN-SUFFIX,responsys.net,AdBlock\n - DOMAIN-SUFFIX,ret.xinlongrubber.com,AdBlock\n - DOMAIN-SUFFIX,rev.fapdu.com,AdBlock\n - DOMAIN-SUFFIX,revdepo.com,AdBlock\n - DOMAIN-SUFFIX,revealads.appspot.com,AdBlock\n - DOMAIN-SUFFIX,revsci.net,AdBlock\n - DOMAIN-SUFFIX,rfir2.50w.me,AdBlock\n - DOMAIN-SUFFIX,rh.code.jjyx.com,AdBlock\n - DOMAIN-SUFFIX,rh.greenbetterkids.com,AdBlock\n - DOMAIN-SUFFIX,rhgyg.com,AdBlock\n - DOMAIN-SUFFIX,rich.kuwo.cn,AdBlock\n - DOMAIN-SUFFIX,richmedia.yimg.com,AdBlock\n - DOMAIN-SUFFIX,riqu2015.com,AdBlock\n - DOMAIN-SUFFIX,river.zhidao.baidu.com,AdBlock\n - DOMAIN-SUFFIX,rj.baidu.com,AdBlock\n - DOMAIN-SUFFIX,rjgw.theta.sogou.com,AdBlock\n - DOMAIN-SUFFIX,rjs.niuxgame77.com,AdBlock\n - DOMAIN-SUFFIX,rk.rongchengxxw.com,AdBlock\n - DOMAIN-SUFFIX,rlcdn.com,AdBlock\n - DOMAIN-SUFFIX,rlogs.youdao.com,AdBlock\n - DOMAIN-SUFFIX,rm.ra.icast.cn,AdBlock\n - DOMAIN-SUFFIX,rm.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,rmads.eu.msn.com,AdBlock\n - DOMAIN-SUFFIX,rmads.msn.com,AdBlock\n - DOMAIN-SUFFIX,rmcxw.cn,AdBlock\n - DOMAIN-SUFFIX,rmoeu.mercury.sogou.com,AdBlock\n - DOMAIN-SUFFIX,rmtx.ra.icast.cn,AdBlock\n - DOMAIN-SUFFIX,rmw.jdburl.com,AdBlock\n - DOMAIN-SUFFIX,rnfrfxqztlno.com,AdBlock\n - DOMAIN-SUFFIX,roia.com,AdBlock\n - DOMAIN-SUFFIX,rosi.okkkk.com,AdBlock\n - DOMAIN-SUFFIX,rotabanner.kulichki.net,AdBlock\n - DOMAIN-SUFFIX,rotate.ymtracking.com,AdBlock\n - DOMAIN-SUFFIX,rotator.tradetracker.net,AdBlock\n - DOMAIN-SUFFIX,router.bittorrent.com,AdBlock\n - DOMAIN-SUFFIX,rovio-news-app.angrybirdsgame.com,AdBlock\n - DOMAIN-SUFFIX,rp.crasheye.cn,AdBlock\n - DOMAIN-SUFFIX,rp.gwallet.com,AdBlock\n - DOMAIN-SUFFIX,rpaulfrank.com,AdBlock\n - DOMAIN-SUFFIX,rpc-php.trafficfactory.biz,AdBlock\n - DOMAIN-SUFFIX,rplog.baidu.com,AdBlock\n - DOMAIN-SUFFIX,rpnews.itaoxiaoshuo.com,AdBlock\n - DOMAIN-SUFFIX,rpt.anchorfree.net,AdBlock\n - DOMAIN-SUFFIX,rqgsf.com,AdBlock\n - DOMAIN-SUFFIX,rr.knet.cn,AdBlock\n - DOMAIN-SUFFIX,rrr.youle55.com,AdBlock\n - DOMAIN-SUFFIX,rrsubway.com,AdBlock\n - DOMAIN-SUFFIX,rs.sinajs.cn,AdBlock\n - DOMAIN-SUFFIX,rs1.rensheng5.com,AdBlock\n - DOMAIN-SUFFIX,rsas.szzek.com,AdBlock\n - DOMAIN-SUFFIX,rsccs.com,AdBlock\n - DOMAIN-SUFFIX,rt.funshion.net,AdBlock\n - DOMAIN-SUFFIX,rt.gsspat.jp,AdBlock\n - DOMAIN-SUFFIX,rtas.videocc.net,AdBlock\n - DOMAIN-SUFFIX,rtax.criteo.com,AdBlock\n - DOMAIN-SUFFIX,rtb.com.ru,AdBlock\n - DOMAIN-SUFFIX,rtb.eanalyzer.de,AdBlock\n - DOMAIN-SUFFIX,rtb.metrigo.com,AdBlock\n - DOMAIN-SUFFIX,rtbasia.com,AdBlock\n - DOMAIN-SUFFIX,rtb-p.kejet.net,AdBlock\n - DOMAIN-SUFFIX,rtbstat.zcdsp.com,AdBlock\n - DOMAIN-SUFFIX,rtlog.vidown.cn,AdBlock\n - DOMAIN-SUFFIX,rtmonitor.kugou.com,AdBlock\n - DOMAIN-SUFFIX,rto.steelhousemedia.com,AdBlock\n - DOMAIN-SUFFIX,ruan88.com,AdBlock\n - DOMAIN-SUFFIX,rubicon-match.dotomi.com,AdBlock\n - DOMAIN-SUFFIX,rubiconproject.com,AdBlock\n - DOMAIN-SUFFIX,rudy.adsnative.com,AdBlock\n - DOMAIN-SUFFIX,ru-gmtdmp.mookie1.com,AdBlock\n - DOMAIN-SUFFIX,rum-collector.pingdom.net,AdBlock\n - DOMAIN-SUFFIX,rum-static.pingdom.net,AdBlock\n - DOMAIN-SUFFIX,runetki.joyreactor.ru,AdBlock\n - DOMAIN-SUFFIX,runiman.com,AdBlock\n - DOMAIN-SUFFIX,rutrk.org,AdBlock\n - DOMAIN-SUFFIX,ruxianke.com,AdBlock\n - DOMAIN-SUFFIX,rvb.quanliyouxi.cn,AdBlock\n - DOMAIN-SUFFIX,rwjfs.com,AdBlock\n - DOMAIN-SUFFIX,rwq.youle55.com,AdBlock\n - DOMAIN-SUFFIX,rxwan.com,AdBlock\n - DOMAIN-SUFFIX,ry51w.cn,AdBlock\n - DOMAIN-SUFFIX,s.0.0.0.0.cn,AdBlock\n - DOMAIN-SUFFIX,s.051352.com,AdBlock\n - DOMAIN-SUFFIX,s.0594529.com,AdBlock\n - DOMAIN-SUFFIX,s.17173cdn.com,AdBlock\n - DOMAIN-SUFFIX,s.35kds.com,AdBlock\n - DOMAIN-SUFFIX,s.5jjx.net,AdBlock\n - DOMAIN-SUFFIX,s.652748.com,AdBlock\n - DOMAIN-SUFFIX,s.6travel.com,AdBlock\n - DOMAIN-SUFFIX,s.abcache.com,AdBlock\n - DOMAIN-SUFFIX,s.alitui.weibo.com,AdBlock\n - DOMAIN-SUFFIX,s.baidu.com,AdBlock\n - DOMAIN-SUFFIX,s.bmgan.com,AdBlock\n - DOMAIN-SUFFIX,s.caduka.cn,AdBlock\n - DOMAIN-SUFFIX,s.cdn.u17t.com,AdBlock\n - DOMAIN-SUFFIX,s.cdxyb.cn,AdBlock\n - DOMAIN-SUFFIX,s.clkservice.youdao.com,AdBlock\n - DOMAIN-SUFFIX,s.com2us.net,AdBlock\n - DOMAIN-SUFFIX,s.coveredsys.cn,AdBlock\n - DOMAIN-SUFFIX,s.cr-nielsen.com,AdBlock\n - DOMAIN-SUFFIX,s.csbew.com,AdBlock\n - DOMAIN-SUFFIX,s.ddstu.com,AdBlock\n - DOMAIN-SUFFIX,s.de123.net,AdBlock\n - DOMAIN-SUFFIX,s.doyo.cn,AdBlock\n - DOMAIN-SUFFIX,s.dpcq1.net,AdBlock\n - DOMAIN-SUFFIX,s.dsjcfw.com,AdBlock\n - DOMAIN-SUFFIX,s.effectivemeasure.net,AdBlock\n - DOMAIN-SUFFIX,s.ekeide.com,AdBlock\n - DOMAIN-SUFFIX,s.georgias.cn,AdBlock\n - DOMAIN-SUFFIX,s.go.sohu.com,AdBlock\n - DOMAIN-SUFFIX,s.haiyunx.com,AdBlock\n - DOMAIN-SUFFIX,s.hk9600.com,AdBlock\n - DOMAIN-SUFFIX,s.hkfuy.com,AdBlock\n - DOMAIN-SUFFIX,s.hnhgw.cn,AdBlock\n - DOMAIN-SUFFIX,s.hzht666.com,AdBlock\n - DOMAIN-SUFFIX,s.img.mix.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,s.iroby.com,AdBlock\n - DOMAIN-SUFFIX,s.iuuff.com,AdBlock\n - DOMAIN-SUFFIX,s.jandan.com,AdBlock\n - DOMAIN-SUFFIX,s.jimdo.com,AdBlock\n - DOMAIN-SUFFIX,s.jlminte.com,AdBlock\n - DOMAIN-SUFFIX,s.jpush.cn,AdBlock\n - DOMAIN-SUFFIX,s.jzkelida.com,AdBlock\n - DOMAIN-SUFFIX,s.khgj.cn,AdBlock\n - DOMAIN-SUFFIX,s.l8l9.com,AdBlock\n - DOMAIN-SUFFIX,s.maipubao.cn,AdBlock\n - DOMAIN-SUFFIX,s.meimeidaren.com,AdBlock\n - DOMAIN-SUFFIX,s.mgwcn.com,AdBlock\n - DOMAIN-SUFFIX,s.mt145.com,AdBlock\n - DOMAIN-SUFFIX,s.okmgy.cn,AdBlock\n - DOMAIN-SUFFIX,s.phpwind.com,AdBlock\n - DOMAIN-SUFFIX,s.qd.qingting.fm,AdBlock\n - DOMAIN-SUFFIX,s.qd.qingtingfm.com,AdBlock\n - DOMAIN-SUFFIX,s.qhupdate.com,AdBlock\n - DOMAIN-SUFFIX,s.qtad.qingting.fm,AdBlock\n - DOMAIN-SUFFIX,s.qzkxt.com,AdBlock\n - DOMAIN-SUFFIX,s.ryre.cn,AdBlock\n - DOMAIN-SUFFIX,s.sh.qihoo.com,AdBlock\n - DOMAIN-SUFFIX,s.shiftrro.com,AdBlock\n - DOMAIN-SUFFIX,s.staqnet.com,AdBlock\n - DOMAIN-SUFFIX,s.temaidi.com,AdBlock\n - DOMAIN-SUFFIX,s.trafficjam.cn,AdBlock\n - DOMAIN-SUFFIX,s.uc627.com,AdBlock\n - DOMAIN-SUFFIX,s.uuidksinc.net,AdBlock\n - DOMAIN-SUFFIX,s.wapadv.com,AdBlock\n - DOMAIN-SUFFIX,s.wrating.com,AdBlock\n - DOMAIN-SUFFIX,s.wxktv.cn,AdBlock\n - DOMAIN-SUFFIX,s.x.cn.xtgreat.com,AdBlock\n - DOMAIN-SUFFIX,s.xcfe.cn,AdBlock\n - DOMAIN-SUFFIX,s.xinghao89.com,AdBlock\n - DOMAIN-SUFFIX,s.xmcmn.com,AdBlock\n - DOMAIN-SUFFIX,s.yanpoly.com,AdBlock\n - DOMAIN-SUFFIX,s.yfycy.com,AdBlock\n - DOMAIN-SUFFIX,s.yidianzixun.com,AdBlock\n - DOMAIN-SUFFIX,s.yjkyj.cn,AdBlock\n - DOMAIN-SUFFIX,s.youmi.net,AdBlock\n - DOMAIN-SUFFIX,s.ysxufeng.com,AdBlock\n - DOMAIN-SUFFIX,s.yunpifu.cn,AdBlock\n - DOMAIN-SUFFIX,s.zgclmw.cn,AdBlock\n - DOMAIN-SUFFIX,s.zixuntop.com,AdBlock\n - DOMAIN-SUFFIX,s.zjhoudao.com,AdBlock\n - DOMAIN-SUFFIX,s.zlongad.com,AdBlock\n - DOMAIN-SUFFIX,s.zxwdw.com,AdBlock\n - DOMAIN-SUFFIX,s0.2mdn.net,AdBlock\n - DOMAIN-SUFFIX,s03.optimix.asia,AdBlock\n - DOMAIN-SUFFIX,s1.2mdn.net,AdBlock\n - DOMAIN-SUFFIX,s1.cmfu.com,AdBlock\n - DOMAIN-SUFFIX,s1.hiapk.com,AdBlock\n - DOMAIN-SUFFIX,s1.hnhbyxdq.com,AdBlock\n - DOMAIN-SUFFIX,s1.huiqituan.com,AdBlock\n - DOMAIN-SUFFIX,s1.iigushi.com,AdBlock\n - DOMAIN-SUFFIX,s1.kutongji.com,AdBlock\n - DOMAIN-SUFFIX,s1.mingmingtehui.com,AdBlock\n - DOMAIN-SUFFIX,s1.qiqutt.cn,AdBlock\n - DOMAIN-SUFFIX,s1.qiqutt.com,AdBlock\n - DOMAIN-SUFFIX,s1.qiuyi.cn,AdBlock\n - DOMAIN-SUFFIX,s1.s8tu.com,AdBlock\n - DOMAIN-SUFFIX,s1.tansuotv.com,AdBlock\n - DOMAIN-SUFFIX,s10.histats.com,AdBlock\n - DOMAIN-SUFFIX,s2.dnaxddnc.com,AdBlock\n - DOMAIN-SUFFIX,s2.hiapk.com,AdBlock\n - DOMAIN-SUFFIX,s2.huoying666.com,AdBlock\n - DOMAIN-SUFFIX,s2.kuaibaopay.com,AdBlock\n - DOMAIN-SUFFIX,s2.mingmingtehui.com,AdBlock\n - DOMAIN-SUFFIX,s2.yandui.com,AdBlock\n - DOMAIN-SUFFIX,s2.zdface.com,AdBlock\n - DOMAIN-SUFFIX,s2.zdmimg.com,AdBlock\n - DOMAIN-SUFFIX,s3.pfp.sina.net,AdBlock\n - DOMAIN-SUFFIX,s3.rongnews.com,AdBlock\n - DOMAIN-SUFFIX,s3d4.cn,AdBlock\n - DOMAIN-SUFFIX,s4.55.la,AdBlock\n - DOMAIN-SUFFIX,s4.histats.com,AdBlock\n - DOMAIN-SUFFIX,s400cc.com,AdBlock\n - DOMAIN-SUFFIX,s5.keydot.net,AdBlock\n - DOMAIN-SUFFIX,s8.001fzc.com,AdBlock\n - DOMAIN-SUFFIX,s8.dnaxddnc.com,AdBlock\n - DOMAIN-SUFFIX,s8x1.com,AdBlock\n - DOMAIN-SUFFIX,s9w.cc,AdBlock\n - DOMAIN-SUFFIX,sa909.com,AdBlock\n - DOMAIN-SUFFIX,sad.qeo.cn,AdBlock\n - DOMAIN-SUFFIX,safe.tsgpay.cn,AdBlock\n - DOMAIN-SUFFIX,safe-aisle.jointreport-switch.com,AdBlock\n - DOMAIN-SUFFIX,saferwet.com,AdBlock\n - DOMAIN-SUFFIX,same.chinadaily.com.cn,AdBlock\n - DOMAIN-SUFFIX,same.eastmoney.com,AdBlock\n - DOMAIN-SUFFIX,same.jrj.com.cn,AdBlock\n - DOMAIN-SUFFIX,same.mzy2014.com,AdBlock\n - DOMAIN-SUFFIX,same.stockstar.com,AdBlock\n - DOMAIN-SUFFIX,same01.jrj.com.cn,AdBlock\n - DOMAIN-SUFFIX,same02.jrj.com.cn,AdBlock\n - DOMAIN-SUFFIX,same03.jrj.com.cn,AdBlock\n - DOMAIN-SUFFIX,sams.nikonimaging.com,AdBlock\n - DOMAIN-SUFFIX,sangxi.top,AdBlock\n - DOMAIN-SUFFIX,sanya1.com,AdBlock\n - DOMAIN-SUFFIX,sape.ru,AdBlock\n - DOMAIN-SUFFIX,sapi.sina.cn,AdBlock\n - DOMAIN-SUFFIX,savebt.net,AdBlock\n - DOMAIN-SUFFIX,saxxaz.taohuayuan8888.com,AdBlock\n - DOMAIN-SUFFIX,sb.scorecardresearch.com,AdBlock\n - DOMAIN-SUFFIX,sb88b.com,AdBlock\n - DOMAIN-SUFFIX,sbeacon.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,sbrqp.com,AdBlock\n - DOMAIN-SUFFIX,sbw.ysjweb.com,AdBlock\n - DOMAIN-SUFFIX,sc.58mingtian.cn,AdBlock\n - DOMAIN-SUFFIX,sc.chinaiiss.com,AdBlock\n - DOMAIN-SUFFIX,sc.ggdoubi.com,AdBlock\n - DOMAIN-SUFFIX,sc.ggfeng.com,AdBlock\n - DOMAIN-SUFFIX,sc.iasds01.com,AdBlock\n - DOMAIN-SUFFIX,sc.sczxy.com,AdBlock\n - DOMAIN-SUFFIX,sc.shayugg.com,AdBlock\n - DOMAIN-SUFFIX,sc1369.com,AdBlock\n - DOMAIN-SUFFIX,scc.0.0.0.0.cn,AdBlock\n - DOMAIN-SUFFIX,sccdn.f2zd.com,AdBlock\n - DOMAIN-SUFFIX,scdng.com,AdBlock\n - DOMAIN-SUFFIX,scdown.qq.com,AdBlock\n - DOMAIN-SUFFIX,scene.vip.xunlei.com,AdBlock\n - DOMAIN-SUFFIX,schborg.com,AdBlock\n - DOMAIN-SUFFIX,schemas.android.com,AdBlock\n - DOMAIN-SUFFIX,schprompt.dangdang.com,AdBlock\n - DOMAIN-SUFFIX,sciencelolb.com,AdBlock\n - DOMAIN-SUFFIX,scimg.27admin.com,AdBlock\n - DOMAIN-SUFFIX,sclick.6rooms.com,AdBlock\n - DOMAIN-SUFFIX,sclick.baidu.com,AdBlock\n - DOMAIN-SUFFIX,sclizhong.com,AdBlock\n - DOMAIN-SUFFIX,sclog.moviebox.baofeng.com,AdBlock\n - DOMAIN-SUFFIX,scorecardresearch.com,AdBlock\n - DOMAIN-SUFFIX,scribe.twitter.com,AdBlock\n - DOMAIN-SUFFIX,scrippsnetworks.com,AdBlock\n - DOMAIN-SUFFIX,script.crazyegg.com,AdBlock\n - DOMAIN-SUFFIX,script.vccoo.com,AdBlock\n - DOMAIN-SUFFIX,script-bd.baixing.net,AdBlock\n - DOMAIN-SUFFIX,scriptcc.cc,AdBlock\n - DOMAIN-SUFFIX,scupio.com,AdBlock\n - DOMAIN-SUFFIX,scw0.com,AdBlock\n - DOMAIN-SUFFIX,sd.0.0.0.0.cn,AdBlock\n - DOMAIN-SUFFIX,sd.kk3g.net,AdBlock\n - DOMAIN-SUFFIX,sdac.lenovomm.com,AdBlock\n - DOMAIN-SUFFIX,sdapprecv.app.cntvwb.cn,AdBlock\n - DOMAIN-SUFFIX,sdb.amazonaws.com,AdBlock\n - DOMAIN-SUFFIX,sdhzstone.net,AdBlock\n - DOMAIN-SUFFIX,sdk.appadhoc.com,AdBlock\n - DOMAIN-SUFFIX,sdk.cdnmaster.com,AdBlock\n - DOMAIN-SUFFIX,sdk.cmgame.com,AdBlock\n - DOMAIN-SUFFIX,sdk.conf.igexin.com,AdBlock\n - DOMAIN-SUFFIX,sdk.mobad.ijinshan.com,AdBlock\n - DOMAIN-SUFFIX,sdk.open.amp.igexin.com,AdBlock\n - DOMAIN-SUFFIX,sdk.open.lbs.igexin.com,AdBlock\n - DOMAIN-SUFFIX,sdk.open.phone.igexin.com,AdBlock\n - DOMAIN-SUFFIX,sdk.open.talk.gepush.com,AdBlock\n - DOMAIN-SUFFIX,sdk.open.talk.igexin.com,AdBlock\n - DOMAIN-SUFFIX,sdkapp.mobile.sina.cn,AdBlock\n - DOMAIN-SUFFIX,sdkapp.uve.weibo.com,AdBlock\n - DOMAIN-SUFFIX,sdkclick.mobile.sina.cn,AdBlock\n - DOMAIN-SUFFIX,sdkconfig.ad.intl.xiaomi.com,AdBlock\n - DOMAIN-SUFFIX,sdkdm.com,AdBlock\n - DOMAIN-SUFFIX,sdklog.cmgame.com,AdBlock\n - DOMAIN-SUFFIX,sdklog.uu.cc,AdBlock\n - DOMAIN-SUFFIX,sdkpay.uu.cc,AdBlock\n - DOMAIN-SUFFIX,sdksitter.m.sjzhushou.com,AdBlock\n - DOMAIN-SUFFIX,sdl.0.0.0.0.cn,AdBlock\n - DOMAIN-SUFFIX,sdn.kugou.com,AdBlock\n - DOMAIN-SUFFIX,sdn.penggua.com.cn,AdBlock\n - DOMAIN-SUFFIX,sdownload.stargame.com,AdBlock\n - DOMAIN-SUFFIX,sdqoi2d.com,AdBlock\n - DOMAIN-SUFFIX,sdwfw.com,AdBlock\n - DOMAIN-SUFFIX,sdycd.com,AdBlock\n - DOMAIN-SUFFIX,sea.napi.ucweb.com,AdBlock\n - DOMAIN-SUFFIX,searchignited.com,AdBlock\n - DOMAIN-SUFFIX,searchswapper.com,AdBlock\n - DOMAIN-SUFFIX,seavideo-ak.espn.go.com,AdBlock\n - DOMAIN-SUFFIX,sebar.thand.info,AdBlock\n - DOMAIN-SUFFIX,sec.resource.xiaomi.net,AdBlock\n - DOMAIN-SUFFIX,secpay.wostore.cn,AdBlock\n - DOMAIN-SUFFIX,secretmedia.s3.amazonaws.com,AdBlock\n - DOMAIN-SUFFIX,secure.dsp.com,AdBlock\n - DOMAIN-SUFFIX,secure.fastclick.net,AdBlock\n - DOMAIN-SUFFIX,secure.img-cdn.mediaplex.com,AdBlock\n - DOMAIN-SUFFIX,secure.quantserve.com,AdBlock\n - DOMAIN-SUFFIX,secure.statcounter.com,AdBlock\n - DOMAIN-SUFFIX,secure-asia.imrworldwide.com,AdBlock\n - DOMAIN-SUFFIX,secure-assets.rubiconproject.com,AdBlock\n - DOMAIN-SUFFIX,secure-chn.imrworldwide.com,AdBlock\n - DOMAIN-SUFFIX,secure-ds.serving-sys.com,AdBlock\n - DOMAIN-SUFFIX,security.browser.miui.com,AdBlock\n - DOMAIN-SUFFIX,seen.h01ce.cn,AdBlock\n - DOMAIN-SUFFIX,seen.hgo7r.cn,AdBlock\n - DOMAIN-SUFFIX,seg.sharethis.com,AdBlock\n - DOMAIN-SUFFIX,segment.com,AdBlock\n - DOMAIN-SUFFIX,selfie.snapmobileasia.net,AdBlock\n - DOMAIN-SUFFIX,sell1.etlong.com,AdBlock\n - DOMAIN-SUFFIX,sensorsdata.ruguoapp.com,AdBlock\n - DOMAIN-SUFFIX,serial.alcohol-soft.com,AdBlock\n - DOMAIN-SUFFIX,serrano.hardwareheaven.com,AdBlock\n - DOMAIN-SUFFIX,serve.popads.net,AdBlock\n - DOMAIN-SUFFIX,servedby.keygamesnetwork.com,AdBlock\n - DOMAIN-SUFFIX,server.m.pp.cn,AdBlock\n - DOMAIN-SUFFIX,service.ad.adesk.com,AdBlock\n - DOMAIN-SUFFIX,service.ad.duomi.com,AdBlock\n - DOMAIN-SUFFIX,service.cocounion.com,AdBlock\n - DOMAIN-SUFFIX,service.danmu.youku.com,AdBlock\n - DOMAIN-SUFFIX,service.epro.sogou.com,AdBlock\n - DOMAIN-SUFFIX,service.urchin.com,AdBlock\n - DOMAIN-SUFFIX,servicer.adskeeper.co.uk,AdBlock\n - DOMAIN-SUFFIX,serving-sys.com,AdBlock\n - DOMAIN-SUFFIX,sestat.baidu.com,AdBlock\n - DOMAIN-SUFFIX,setting.crashlytics.com,AdBlock\n - DOMAIN-SUFFIX,setting.rayjump.com,AdBlock\n - DOMAIN-SUFFIX,setting.snswin.qq.com,AdBlock\n - DOMAIN-SUFFIX,settings.crashlytics.com,AdBlock\n - DOMAIN-SUFFIX,sezvc.com,AdBlock\n - DOMAIN-SUFFIX,sf3-fe-tos.pglstatp-toutiao.com,AdBlock\n - DOMAIN-SUFFIX,sfloushi.com,AdBlock\n - DOMAIN-SUFFIX,sg536.cn,AdBlock\n - DOMAIN-SUFFIX,sgbfjs.info,AdBlock\n - DOMAIN-SUFFIX,sg-cdn.effectivemeasure.net,AdBlock\n - DOMAIN-SUFFIX,sgg.southcn.com,AdBlock\n - DOMAIN-SUFFIX,sgvip.chinahdcm.com,AdBlock\n - DOMAIN-SUFFIX,sh.qihoo.com,AdBlock\n - DOMAIN-SUFFIX,sh.shuqw.com,AdBlock\n - DOMAIN-SUFFIX,sha50.com,AdBlock\n - DOMAIN-SUFFIX,shadu.baidu.com,AdBlock\n - DOMAIN-SUFFIX,shaft.jebe.renren.com,AdBlock\n - DOMAIN-SUFFIX,shama5.com,AdBlock\n - DOMAIN-SUFFIX,shanghaironghua.com,AdBlock\n - DOMAIN-SUFFIX,shanglinli.com,AdBlock\n - DOMAIN-SUFFIX,shangz99991.com,AdBlock\n - DOMAIN-SUFFIX,shankejingling.com,AdBlock\n - DOMAIN-SUFFIX,share.gzdsw.com,AdBlock\n - DOMAIN-SUFFIX,shared.youdao.com,AdBlock\n - DOMAIN-SUFFIX,sharedaddomain.com,AdBlock\n - DOMAIN-SUFFIX,sharrysweb.com,AdBlock\n - DOMAIN-SUFFIX,shbywsd.cn,AdBlock\n - DOMAIN-SUFFIX,shenghuo.xiaomi.com,AdBlock\n - DOMAIN-SUFFIX,shenleyuni.com,AdBlock\n - DOMAIN-SUFFIX,shenyian.net,AdBlock\n - DOMAIN-SUFFIX,shenyun.com,AdBlock\n - DOMAIN-SUFFIX,shenyun.org,AdBlock\n - DOMAIN-SUFFIX,shenyunperformingarts.org,AdBlock\n - DOMAIN-SUFFIX,shglegle.com,AdBlock\n - DOMAIN-SUFFIX,shibeiou.com,AdBlock\n - DOMAIN-SUFFIX,shiftrro.com,AdBlock\n - DOMAIN-SUFFIX,shili.downxia.com,AdBlock\n - DOMAIN-SUFFIX,shili.wanyx.com,AdBlock\n - DOMAIN-SUFFIX,shiwan.dl.gxpan.cn,AdBlock\n - DOMAIN-SUFFIX,shixunjs.th21333.com,AdBlock\n - DOMAIN-SUFFIX,shke.kuuad.com,AdBlock\n - DOMAIN-SUFFIX,shop.admin.yinyuetai.com,AdBlock\n - DOMAIN-SUFFIX,shop.yinyuetai.com,AdBlock\n - DOMAIN-SUFFIX,shop265.com,AdBlock\n - DOMAIN-SUFFIX,shoppingpartners2.futurenet.com,AdBlock\n - DOMAIN-SUFFIX,shouyoutan.com,AdBlock\n - DOMAIN-SUFFIX,show.kc.taotaosou.com,AdBlock\n - DOMAIN-SUFFIX,show.qx15.com,AdBlock\n - DOMAIN-SUFFIX,show.xiazai16.com,AdBlock\n - DOMAIN-SUFFIX,showcase.vpsboard.com,AdBlock\n - DOMAIN-SUFFIX,showing.hardwareheaven.com,AdBlock\n - DOMAIN-SUFFIX,shows.21cn.com,AdBlock\n - DOMAIN-SUFFIX,shtt.shuqw.com,AdBlock\n - DOMAIN-SUFFIX,shucaihangjia.com,AdBlock\n - DOMAIN-SUFFIX,shuiguo.com,AdBlock\n - DOMAIN-SUFFIX,shuqw.com,AdBlock\n - DOMAIN-SUFFIX,shushijiameng123.com,AdBlock\n - DOMAIN-SUFFIX,shuttle.bayescom.com,AdBlock\n - DOMAIN-SUFFIX,shuzilm.cn,AdBlock\n - DOMAIN-SUFFIX,shxinjie.cn,AdBlock\n - DOMAIN-SUFFIX,shzyjbr.wtdtjs.rocks,AdBlock\n - DOMAIN-SUFFIX,si9377.com,AdBlock\n - DOMAIN-SUFFIX,sicentlife.com,AdBlock\n - DOMAIN-SUFFIX,sifubo.cn,AdBlock\n - DOMAIN-SUFFIX,sifuce.cn,AdBlock\n - DOMAIN-SUFFIX,sifuda.cn,AdBlock\n - DOMAIN-SUFFIX,sifufu.cn,AdBlock\n - DOMAIN-SUFFIX,sifuge.cn,AdBlock\n - DOMAIN-SUFFIX,sifugu.cn,AdBlock\n - DOMAIN-SUFFIX,sifuhe.cn,AdBlock\n - DOMAIN-SUFFIX,sifuhu.cn,AdBlock\n - DOMAIN-SUFFIX,sifuji.cn,AdBlock\n - DOMAIN-SUFFIX,sifuka.cn,AdBlock\n - DOMAIN-SUFFIX,sigbusa.com,AdBlock\n - DOMAIN-SUFFIX,sigo99.com,AdBlock\n - DOMAIN-SUFFIX,simba.m.taobao.com,AdBlock\n - DOMAIN-SUFFIX,sina.wrating.com,AdBlock\n - DOMAIN-SUFFIX,sina.yinstar.org,AdBlock\n - DOMAIN-SUFFIX,sinaalicdn.com,AdBlock\n - DOMAIN-SUFFIX,sinaaliyun.cn,AdBlock\n - DOMAIN-SUFFIX,siqwqjza.m.yikanxiaoshuo.net,AdBlock\n - DOMAIN-SUFFIX,sis.jpush.io,AdBlock\n - DOMAIN-SUFFIX,sit.gentags.net,AdBlock\n - DOMAIN-SUFFIX,sit.pagechoice.net,AdBlock\n - DOMAIN-SUFFIX,site.cdnmaster.com,AdBlock\n - DOMAIN-SUFFIX,site.img.4tube.com,AdBlock\n - DOMAIN-SUFFIX,sitemeter.com,AdBlock\n - DOMAIN-SUFFIX,sitemobia.com,AdBlock\n - DOMAIN-SUFFIX,sitescout.com,AdBlock\n - DOMAIN-SUFFIX,sitetag.us,AdBlock\n - DOMAIN-SUFFIX,sj.uukanshu.com,AdBlock\n - DOMAIN-SUFFIX,sj1.3987.com,AdBlock\n - DOMAIN-SUFFIX,sjj.jsyjwj.com,AdBlock\n - DOMAIN-SUFFIX,skatehot.net,AdBlock\n - DOMAIN-SUFFIX,sl.xawjwl.com,AdBlock\n - DOMAIN-SUFFIX,slb.sxuantang.com,AdBlock\n - DOMAIN-SUFFIX,slb.upshengyi.com,AdBlock\n - DOMAIN-SUFFIX,slib.tvmao.cn,AdBlock\n - DOMAIN-SUFFIX,slides.discovery.tom.com,AdBlock\n - DOMAIN-SUFFIX,slog.sina.cn,AdBlock\n - DOMAIN-SUFFIX,slog.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,slot.union.ucweb.com,AdBlock\n - DOMAIN-SUFFIX,slzs.52xiyou.com,AdBlock\n - DOMAIN-SUFFIX,sm.0.0.0.0.cn,AdBlock\n - DOMAIN-SUFFIX,sm1.todgo.com,AdBlock\n - DOMAIN-SUFFIX,sm2.todgo.com,AdBlock\n - DOMAIN-SUFFIX,smartmad.com,AdBlock\n - DOMAIN-SUFFIX,smblock.s3.amazonaws.com,AdBlock\n - DOMAIN-SUFFIX,smgru.net,AdBlock\n - DOMAIN-SUFFIX,smucdn.com,AdBlock\n - DOMAIN-SUFFIX,smxay.com,AdBlock\n - DOMAIN-SUFFIX,smxsg.com,AdBlock\n - DOMAIN-SUFFIX,snap.snapmobile.asia,AdBlock\n - DOMAIN-SUFFIX,snapmobileasia.net,AdBlock\n - DOMAIN-SUFFIX,sngmta.qq.com,AdBlock\n - DOMAIN-SUFFIX,snnnyy.com,AdBlock\n - DOMAIN-SUFFIX,snow001.com,AdBlock\n - DOMAIN-SUFFIX,so9l.com,AdBlock\n - DOMAIN-SUFFIX,soarfi.cn,AdBlock\n - DOMAIN-SUFFIX,sobar.baidu.com,AdBlock\n - DOMAIN-SUFFIX,sobartop.baidu.com,AdBlock\n - DOMAIN-SUFFIX,social-touch.com,AdBlock\n - DOMAIN-SUFFIX,sod.onelink.me,AdBlock\n - DOMAIN-SUFFIX,soft.chaomeng8.com,AdBlock\n - DOMAIN-SUFFIX,soft.zhidian3g.cn,AdBlock\n - DOMAIN-SUFFIX,sohu.irs01.com,AdBlock\n - DOMAIN-SUFFIX,sohu.wrating.com,AdBlock\n - DOMAIN-SUFFIX,somecoding.com,AdBlock\n - DOMAIN-SUFFIX,somennew.com,AdBlock\n - DOMAIN-SUFFIX,song.fanxing.kugou.com,AdBlock\n - DOMAIN-SUFFIX,song001.com,AdBlock\n - DOMAIN-SUFFIX,sonomoyo.com,AdBlock\n - DOMAIN-SUFFIX,sos0easy.com,AdBlock\n - DOMAIN-SUFFIX,sou.dkdlsj.com,AdBlock\n - DOMAIN-SUFFIX,sou.xanbhx.com,AdBlock\n - DOMAIN-SUFFIX,souid.com,AdBlock\n - DOMAIN-SUFFIX,source.youxiaoad.com,AdBlock\n - DOMAIN-SUFFIX,sousuo.xm.sjzhushou.com,AdBlock\n - DOMAIN-SUFFIX,sp.fastclick.net,AdBlock\n - DOMAIN-SUFFIX,sp.gmossp-sp.jp,AdBlock\n - DOMAIN-SUFFIX,sp.wndoor.com,AdBlock\n - DOMAIN-SUFFIX,sp.yixui.com,AdBlock\n - DOMAIN-SUFFIX,sp3.cndm.com,AdBlock\n - DOMAIN-SUFFIX,spad.i-mobile.co.jp,AdBlock\n - DOMAIN-SUFFIX,spade.twitch.tv,AdBlock\n - DOMAIN-SUFFIX,spap.adingo.jp,AdBlock\n - DOMAIN-SUFFIX,spap.adingo.jp.eimg.jp,AdBlock\n - DOMAIN-SUFFIX,spapi.i-mobile.co.jp,AdBlock\n - DOMAIN-SUFFIX,spb.bid.run,AdBlock\n - DOMAIN-SUFFIX,spcdnpc.i-mobile.co.jp,AdBlock\n - DOMAIN-SUFFIX,spcnv.i-mobile.co.jp,AdBlock\n - DOMAIN-SUFFIX,spcode.baidu.com,AdBlock\n - DOMAIN-SUFFIX,spdeliver.i-mobile.co.jp,AdBlock\n - DOMAIN-SUFFIX,spdmg.i-mobile.co.jp,AdBlock\n - DOMAIN-SUFFIX,spdmg-backend.i-mobile.co.jp,AdBlock\n - DOMAIN-SUFFIX,sphwq.net,AdBlock\n - DOMAIN-SUFFIX,spnet2-1.i-mobile.co.jp,AdBlock\n - DOMAIN-SUFFIX,spnet33.i-mobile.co.jp,AdBlock\n - DOMAIN-SUFFIX,sponsorpay.com,AdBlock\n - DOMAIN-SUFFIX,sponsors.s2ki.com,AdBlock\n - DOMAIN-SUFFIX,sponsors.webosroundup.com,AdBlock\n - DOMAIN-SUFFIX,spproxy.autobytel.com,AdBlock\n - DOMAIN-SUFFIX,spro.so.com,AdBlock\n - DOMAIN-SUFFIX,spt.dictionary.com,AdBlock\n - DOMAIN-SUFFIX,sqd.jstdjq.com,AdBlock\n - DOMAIN-SUFFIX,sqext.com,AdBlock\n - DOMAIN-SUFFIX,sqtpks3.1391.com,AdBlock\n - DOMAIN-SUFFIX,squarespace.evyy.net,AdBlock\n - DOMAIN-SUFFIX,src.duanxin520.com,AdBlock\n - DOMAIN-SUFFIX,src.leju.com,AdBlock\n - DOMAIN-SUFFIX,src.zf313.com,AdBlock\n - DOMAIN-SUFFIX,srd.simba.taobao.com,AdBlock\n - DOMAIN-SUFFIX,srhuafeng.com,AdBlock\n - DOMAIN-SUFFIX,srv.carbonads.net,AdBlock\n - DOMAIN-SUFFIX,srv.revdepo.com,AdBlock\n - DOMAIN-SUFFIX,srv.thespacereporter.com,AdBlock\n - DOMAIN-SUFFIX,ss.cnczjy.com,AdBlock\n - DOMAIN-SUFFIX,ss.cnnic.cn,AdBlock\n - DOMAIN-SUFFIX,ss.he9630.com,AdBlock\n - DOMAIN-SUFFIX,ss.knet.cn,AdBlock\n - DOMAIN-SUFFIX,ss.missyouxi.com,AdBlock\n - DOMAIN-SUFFIX,ss.shicimingju.com,AdBlock\n - DOMAIN-SUFFIX,ss.shuajuzu.com,AdBlock\n - DOMAIN-SUFFIX,ss.subo.me,AdBlock\n - DOMAIN-SUFFIX,ss.swagger1.com,AdBlock\n - DOMAIN-SUFFIX,ss.sysad.cn,AdBlock\n - DOMAIN-SUFFIX,ss.sysadult.cn,AdBlock\n - DOMAIN-SUFFIX,ssac.suning.com,AdBlock\n - DOMAIN-SUFFIX,sscefsol.com,AdBlock\n - DOMAIN-SUFFIX,sscefsol.com.cn,AdBlock\n - DOMAIN-SUFFIX,ssdaili.com,AdBlock\n - DOMAIN-SUFFIX,ssh.hxlif.com,AdBlock\n - DOMAIN-SUFFIX,ssh.jsyzw132.com,AdBlock\n - DOMAIN-SUFFIX,ssh.lifu11.com,AdBlock\n - DOMAIN-SUFFIX,ssh.szxiuchang.com,AdBlock\n - DOMAIN-SUFFIX,ssh.yezijizhang.com,AdBlock\n - DOMAIN-SUFFIX,ssjpx.com,AdBlock\n - DOMAIN-SUFFIX,ssjy168.com,AdBlock\n - DOMAIN-SUFFIX,ssl.google-analytics.com,AdBlock\n - DOMAIN-SUFFIX,ssl.hyhzy.cn,AdBlock\n - DOMAIN-SUFFIX,ssl.ymapp.com,AdBlock\n - DOMAIN-SUFFIX,ssl-cdn.media.innity.net,AdBlock\n - DOMAIN-SUFFIX,sso-cas.gridsumdissector.com,AdBlock\n - DOMAIN-SUFFIX,ssp.08160.cn,AdBlock\n - DOMAIN-SUFFIX,ssp.1rtb.com,AdBlock\n - DOMAIN-SUFFIX,ssp.4hw.com.cn,AdBlock\n - DOMAIN-SUFFIX,ssp.86str.com,AdBlock\n - DOMAIN-SUFFIX,ssp.chaohutechan.com,AdBlock\n - DOMAIN-SUFFIX,ssp.cibn.starschina.com,AdBlock\n - DOMAIN-SUFFIX,ssp.daxueshengqiandai.com,AdBlock\n - DOMAIN-SUFFIX,ssp.dmpdsp.com,AdBlock\n - DOMAIN-SUFFIX,ssp.kjwx8.com,AdBlock\n - DOMAIN-SUFFIX,ssp.kss.ksyun.com,AdBlock\n - DOMAIN-SUFFIX,ssp.kssws.ks-cdn.com,AdBlock\n - DOMAIN-SUFFIX,ssp.kxly360.com,AdBlock\n - DOMAIN-SUFFIX,ssp.pro.cn,AdBlock\n - DOMAIN-SUFFIX,ssp.tadseeker.com,AdBlock\n - DOMAIN-SUFFIX,ssp.thescenseproject.com,AdBlock\n - DOMAIN-SUFFIX,ssp.youxiaoad.com,AdBlock\n - DOMAIN-SUFFIX,ssp.zf313.com,AdBlock\n - DOMAIN-SUFFIX,ssp1.dmpdsp.com,AdBlock\n - DOMAIN-SUFFIX,sspapi.youxiaoad.com,AdBlock\n - DOMAIN-SUFFIX,ssp-bidder.i-mobile.co.jp,AdBlock\n - DOMAIN-SUFFIX,ssp-rtb.sape.ru,AdBlock\n - DOMAIN-SUFFIX,sss.jusha.com,AdBlock\n - DOMAIN-SUFFIX,sss.sege.xxx,AdBlock\n - DOMAIN-SUFFIX,sss.soarfi.cn,AdBlock\n - DOMAIN-SUFFIX,sss.wzjmr.com,AdBlock\n - DOMAIN-SUFFIX,sss.zbred.com,AdBlock\n - DOMAIN-SUFFIX,sssvd.china.com,AdBlock\n - DOMAIN-SUFFIX,sstc360.com,AdBlock\n - DOMAIN-SUFFIX,ssum.casalemedia.com,AdBlock\n - DOMAIN-SUFFIX,st.holalauncher.com,AdBlock\n - DOMAIN-SUFFIX,st.holaworld.cn,AdBlock\n - DOMAIN-SUFFIX,st.targetix.net,AdBlock\n - DOMAIN-SUFFIX,st.yandexadexchange.net,AdBlock\n - DOMAIN-SUFFIX,st.yengo.com,AdBlock\n - DOMAIN-SUFFIX,sta.ganji.com,AdBlock\n - DOMAIN-SUFFIX,sta.haloall.com,AdBlock\n - DOMAIN-SUFFIX,sta.holagames.com,AdBlock\n - DOMAIN-SUFFIX,sta.jcjk0451.com,AdBlock\n - DOMAIN-SUFFIX,stadig.ifeng.com,AdBlock\n - DOMAIN-SUFFIX,stadig0.ifeng.com,AdBlock\n - DOMAIN-SUFFIX,staging.admin.e.mi.com,AdBlock\n - DOMAIN-SUFFIX,staqnet.com,AdBlock\n - DOMAIN-SUFFIX,star8.net,AdBlock\n - DOMAIN-SUFFIX,startapp.com,AdBlock\n - DOMAIN-SUFFIX,startappexchange.com,AdBlock\n - DOMAIN-SUFFIX,startappservice.com,AdBlock\n - DOMAIN-SUFFIX,startup.oupeng.com,AdBlock\n - DOMAIN-SUFFIX,static1.kewaishu.info,AdBlock\n - DOMAIN-SUFFIX,staticadm.leju.com,AdBlock\n - DOMAIN-SUFFIX,staticadm.leju.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,staticjs.cn,AdBlock\n - DOMAIN-SUFFIX,statics.3987.com,AdBlock\n - DOMAIN-SUFFIX,statics.9669.com,AdBlock\n - DOMAIN-SUFFIX,statics.woozooo.com,AdBlock\n - DOMAIN-SUFFIX,statictest.fraudmetrix.cn,AdBlock\n - DOMAIN-SUFFIX,static-xl9-ssl.xunlei.com,AdBlock\n - DOMAIN-SUFFIX,staticxx.facebook.com,AdBlock\n - DOMAIN-SUFFIX,statisticsv2.yinyuetai.com,AdBlock\n - DOMAIN-SUFFIX,stat-y.xywy.com,AdBlock\n - DOMAIN-SUFFIX,stat-z.xywy.com,AdBlock\n - DOMAIN-SUFFIX,steelhousemedia.com,AdBlock\n - DOMAIN-SUFFIX,stervapoimenialena.info,AdBlock\n - DOMAIN-SUFFIX,stg8.com,AdBlock\n - DOMAIN-SUFFIX,stjzh.gdtarget.com,AdBlock\n - DOMAIN-SUFFIX,st-n.ads3-adnow.com,AdBlock\n - DOMAIN-SUFFIX,stn88.com,AdBlock\n - DOMAIN-SUFFIX,stocksbsc.com,AdBlock\n - DOMAIN-SUFFIX,storeconfig.mistat.xiaomi.com,AdBlock\n - DOMAIN-SUFFIX,storewidget.pcauthority.com.au,AdBlock\n - DOMAIN-SUFFIX,stream.heavenmedia.net,AdBlock\n - DOMAIN-SUFFIX,stream.shuzilm.cn,AdBlock\n - DOMAIN-SUFFIX,streaming.rtbiddingplatform.com,AdBlock\n - DOMAIN-SUFFIX,strip.alicdn.com,AdBlock\n - DOMAIN-SUFFIX,strip.taobaocdn.com,AdBlock\n - DOMAIN-SUFFIX,su.8881919.cc,AdBlock\n - DOMAIN-SUFFIX,su.bdimg.com,AdBlock\n - DOMAIN-SUFFIX,su.bdstatic.com,AdBlock\n - DOMAIN-SUFFIX,sub.powerapple.com,AdBlock\n - DOMAIN-SUFFIX,sub.topber.com,AdBlock\n - DOMAIN-SUFFIX,subswin.com,AdBlock\n - DOMAIN-SUFFIX,sucodb.com,AdBlock\n - DOMAIN-SUFFIX,sunjianhao.com,AdBlock\n - DOMAIN-SUFFIX,suoooi.cn,AdBlock\n - DOMAIN-SUFFIX,super.cat898.com,AdBlock\n - DOMAIN-SUFFIX,super.kdnet.net,AdBlock\n - DOMAIN-SUFFIX,supfast.net,AdBlock\n - DOMAIN-SUFFIX,surv.xbizmedia.com,AdBlock\n - DOMAIN-SUFFIX,susapi.dev.surepush.cn,AdBlock\n - DOMAIN-SUFFIX,susapi.lenovomm.com,AdBlock\n - DOMAIN-SUFFIX,suvset.sohu.com,AdBlock\n - DOMAIN-SUFFIX,sv719.dreamdays.cn,AdBlock\n - DOMAIN-SUFFIX,sw.cailawyer.cn,AdBlock\n - DOMAIN-SUFFIX,sw.mobile.sogou.com,AdBlock\n - DOMAIN-SUFFIX,swa.gtimg.com,AdBlock\n - DOMAIN-SUFFIX,swappdl.duoyi.com,AdBlock\n - DOMAIN-SUFFIX,switchadhub.com,AdBlock\n - DOMAIN-SUFFIX,switching.atm.punchbox.org,AdBlock\n - DOMAIN-SUFFIX,swpgjai.pop.weddingeeos.com,AdBlock\n - DOMAIN-SUFFIX,swx.0.0.0.0.cn,AdBlock\n - DOMAIN-SUFFIX,sxbhzs.net,AdBlock\n - DOMAIN-SUFFIX,sxdyrq.com,AdBlock\n - DOMAIN-SUFFIX,sxjxhg.com,AdBlock\n - DOMAIN-SUFFIX,sxz67.com,AdBlock\n - DOMAIN-SUFFIX,sy.code.mytanwan.com,AdBlock\n - DOMAIN-SUFFIX,sy.flash.mytanwan.com,AdBlock\n - DOMAIN-SUFFIX,sy.jlhygy.com,AdBlock\n - DOMAIN-SUFFIX,sy.kcxsyz.com,AdBlock\n - DOMAIN-SUFFIX,sy.shongcheng.com,AdBlock\n - DOMAIN-SUFFIX,sy.sxjxhg.com,AdBlock\n - DOMAIN-SUFFIX,sycbbs.com,AdBlock\n - DOMAIN-SUFFIX,sy-cdnres.unionsy.com,AdBlock\n - DOMAIN-SUFFIX,syilm.net,AdBlock\n - DOMAIN-SUFFIX,sykty.com,AdBlock\n - DOMAIN-SUFFIX,symaj.cn,AdBlock\n - DOMAIN-SUFFIX,synacast.com,AdBlock\n - DOMAIN-SUFFIX,sync.1dmp.io,AdBlock\n - DOMAIN-SUFFIX,sync.1rx.io,AdBlock\n - DOMAIN-SUFFIX,sync.adotmob.com,AdBlock\n - DOMAIN-SUFFIX,sync.audsp.com,AdBlock\n - DOMAIN-SUFFIX,sync.audtd.com,AdBlock\n - DOMAIN-SUFFIX,sync.crwdcntrl.net,AdBlock\n - DOMAIN-SUFFIX,sync.extend.tv,AdBlock\n - DOMAIN-SUFFIX,sync.fastclick.net,AdBlock\n - DOMAIN-SUFFIX,sync.intentiq.com,AdBlock\n - DOMAIN-SUFFIX,sync.ipredictive.com,AdBlock\n - DOMAIN-SUFFIX,sync.mathtag.com,AdBlock\n - DOMAIN-SUFFIX,sync.morgdm.ru,AdBlock\n - DOMAIN-SUFFIX,sync.rambler.ru,AdBlock\n - DOMAIN-SUFFIX,sync.republer.com,AdBlock\n - DOMAIN-SUFFIX,sync.teamrtb.net,AdBlock\n - DOMAIN-SUFFIX,sync.tidaltv.com,AdBlock\n - DOMAIN-SUFFIX,sync2.audtd.com,AdBlock\n - DOMAIN-SUFFIX,sync-dsp.ad-m.asia,AdBlock\n - DOMAIN-SUFFIX,sync-eu.exe.bid,AdBlock\n - DOMAIN-SUFFIX,sync-tm.everesttech.net,AdBlock\n - DOMAIN-SUFFIX,syndication.exdynsrv.com,AdBlock\n - DOMAIN-SUFFIX,syndication.exoclick.com,AdBlock\n - DOMAIN-SUFFIX,syndication.intel.com,AdBlock\n - DOMAIN-SUFFIX,syndication.jsadapi.com,AdBlock\n - DOMAIN-SUFFIX,syndication.twitter.com,AdBlock\n - DOMAIN-SUFFIX,syndication1.viraladnetwork.net,AdBlock\n - DOMAIN-SUFFIX,syndication-o.twitter.com,AdBlock\n - DOMAIN-SUFFIX,syofew6o.net,AdBlock\n - DOMAIN-SUFFIX,sys.zhangyue.com,AdBlock\n - DOMAIN-SUFFIX,sysdig.com,AdBlock\n - DOMAIN-SUFFIX,sytcyf.com,AdBlock\n - DOMAIN-SUFFIX,sytsr.com,AdBlock\n - DOMAIN-SUFFIX,sytz1288.com,AdBlock\n - DOMAIN-SUFFIX,szb.aiyole.com,AdBlock\n - DOMAIN-SUFFIX,szdzbx.com,AdBlock\n - DOMAIN-SUFFIX,szfaq.com,AdBlock\n - DOMAIN-SUFFIX,szggdw.com,AdBlock\n - DOMAIN-SUFFIX,szkdst.com,AdBlock\n - DOMAIN-SUFFIX,szrk3.com,AdBlock\n - DOMAIN-SUFFIX,szshouzhai.com,AdBlock\n - DOMAIN-SUFFIX,szxc868.com,AdBlock\n - DOMAIN-SUFFIX,szxpsg.com,AdBlock\n - DOMAIN-SUFFIX,szyr474.com,AdBlock\n - DOMAIN-SUFFIX,t.2d-c.cn,AdBlock\n - DOMAIN-SUFFIX,t.3apf.com,AdBlock\n - DOMAIN-SUFFIX,t.adbxb.cn,AdBlock\n - DOMAIN-SUFFIX,t.adcrops.net,AdBlock\n - DOMAIN-SUFFIX,t.adxchina.cn,AdBlock\n - DOMAIN-SUFFIX,t.atpanel.com,AdBlock\n - DOMAIN-SUFFIX,t.cnsjx.net,AdBlock\n - DOMAIN-SUFFIX,t.collect.yinyuetai.com,AdBlock\n - DOMAIN-SUFFIX,t.cr-nielsen.com,AdBlock\n - DOMAIN-SUFFIX,t.cyuew.com,AdBlock\n - DOMAIN-SUFFIX,t.d.yoyi.tv,AdBlock\n - DOMAIN-SUFFIX,t.dangdang.com,AdBlock\n - DOMAIN-SUFFIX,t.dmtrck.com,AdBlock\n - DOMAIN-SUFFIX,t.go.sohu.com,AdBlock\n - DOMAIN-SUFFIX,t.growingio.com,AdBlock\n - DOMAIN-SUFFIX,t.iz55.com,AdBlock\n - DOMAIN-SUFFIX,t.oq68.com,AdBlock\n - DOMAIN-SUFFIX,t.pingzei.com,AdBlock\n - DOMAIN-SUFFIX,t.qiuqiuqipai.com,AdBlock\n - DOMAIN-SUFFIX,t.sj.qq.com,AdBlock\n - DOMAIN-SUFFIX,t.supermario.xyz,AdBlock\n - DOMAIN-SUFFIX,t.trafmag.com,AdBlock\n - DOMAIN-SUFFIX,t.tzcccm.com,AdBlock\n - DOMAIN-SUFFIX,t.ujian.cc,AdBlock\n - DOMAIN-SUFFIX,t.uvcourse.net,AdBlock\n - DOMAIN-SUFFIX,t.youmi.net,AdBlock\n - DOMAIN-SUFFIX,t1.58cdn.com.cn,AdBlock\n - DOMAIN-SUFFIX,t1.jzkapp.com,AdBlock\n - DOMAIN-SUFFIX,t1.visualrevenue.com,AdBlock\n - DOMAIN-SUFFIX,t1.wshufa.com,AdBlock\n - DOMAIN-SUFFIX,t188.dazhonghua.cn,AdBlock\n - DOMAIN-SUFFIX,t2.58cdn.com.cn,AdBlock\n - DOMAIN-SUFFIX,t2.jzkapp.com,AdBlock\n - DOMAIN-SUFFIX,t2.vbxx.net,AdBlock\n - DOMAIN-SUFFIX,t2.wshufa.com,AdBlock\n - DOMAIN-SUFFIX,t3.58cdn.com.cn,AdBlock\n - DOMAIN-SUFFIX,t70123.com,AdBlock\n - DOMAIN-SUFFIX,t75.qyqc4s.com,AdBlock\n - DOMAIN-SUFFIX,ta.qq.com,AdBlock\n - DOMAIN-SUFFIX,ta80.com,AdBlock\n - DOMAIN-SUFFIX,taat00889.com,AdBlock\n - DOMAIN-SUFFIX,tactics.bainv.net,AdBlock\n - DOMAIN-SUFFIX,tad.suning.com,AdBlock\n - DOMAIN-SUFFIX,tag.cdnmaster.cn,AdBlock\n - DOMAIN-SUFFIX,tag.digitaltarget.ru,AdBlock\n - DOMAIN-SUFFIX,tags.growingio.com,AdBlock\n - DOMAIN-SUFFIX,tags2.adshell.net,AdBlock\n - DOMAIN-SUFFIX,tags4.revdepo.com,AdBlock\n - DOMAIN-SUFFIX,tajs.qq.com,AdBlock\n - DOMAIN-SUFFIX,tajxgs.com,AdBlock\n - DOMAIN-SUFFIX,talk.nz.igexin.com,AdBlock\n - DOMAIN-SUFFIX,tangoutianxia.com,AdBlock\n - DOMAIN-SUFFIX,tansuotv.com,AdBlock\n - DOMAIN-SUFFIX,tanwanyx.com,AdBlock\n - DOMAIN-SUFFIX,tanx.com,AdBlock\n - DOMAIN-SUFFIX,tanxlog.istreamsche.com,AdBlock\n - DOMAIN-SUFFIX,tanzanite.infomine.com,AdBlock\n - DOMAIN-SUFFIX,taobaly.cn,AdBlock\n - DOMAIN-SUFFIX,taobaoaliyun.cn,AdBlock\n - DOMAIN-SUFFIX,taobaobo5.com,AdBlock\n - DOMAIN-SUFFIX,taobayun.cn,AdBlock\n - DOMAIN-SUFFIX,taoggou.com,AdBlock\n - DOMAIN-SUFFIX,taohanpai.com,AdBlock\n - DOMAIN-SUFFIX,taomato.com,AdBlock\n - DOMAIN-SUFFIX,tap.rubiconproject.com,AdBlock\n - DOMAIN-SUFFIX,tap-cdn.rubiconproject.com,AdBlock\n - DOMAIN-SUFFIX,tapjoy.cn,AdBlock\n - DOMAIN-SUFFIX,tapjoy.com,AdBlock\n - DOMAIN-SUFFIX,tapjoyads.com,AdBlock\n - DOMAIN-SUFFIX,tap-t.rubiconproject.com,AdBlock\n - DOMAIN-SUFFIX,targetedinfo.com,AdBlock\n - DOMAIN-SUFFIX,targetedmedia.com.cn,AdBlock\n - DOMAIN-SUFFIX,targetedtopic.com,AdBlock\n - DOMAIN-SUFFIX,tatagou.com.cn,AdBlock\n - DOMAIN-SUFFIX,tb.code.twyxi.com,AdBlock\n - DOMAIN-SUFFIX,tb060x.corp.youdao.com,AdBlock\n - DOMAIN-SUFFIX,tb104x.corp.youdao.com,AdBlock\n - DOMAIN-SUFFIX,tbaocdn.com,AdBlock\n - DOMAIN-SUFFIX,tbjfw.com,AdBlock\n - DOMAIN-SUFFIX,tc.51la.net,AdBlock\n - DOMAIN-SUFFIX,tc.ci123.com,AdBlock\n - DOMAIN-SUFFIX,tc600.com,AdBlock\n - DOMAIN-SUFFIX,tcad.wedolook.com,AdBlock\n - DOMAIN-SUFFIX,tcjy66.cc,AdBlock\n - DOMAIN-SUFFIX,tcss.qq.com,AdBlock\n - DOMAIN-SUFFIX,tcxshop.com,AdBlock\n - DOMAIN-SUFFIX,td.mpush.cn,AdBlock\n - DOMAIN-SUFFIX,td.xue63.com,AdBlock\n - DOMAIN-SUFFIX,tdayi.com,AdBlock\n - DOMAIN-SUFFIX,t-e.flyme.cn,AdBlock\n - DOMAIN-SUFFIX,teen.77rog.com,AdBlock\n - DOMAIN-SUFFIX,telstra.imrworldwide.com,AdBlock\n - DOMAIN-SUFFIX,temai.snssdk.com,AdBlock\n - DOMAIN-SUFFIX,temai.taobao.com,AdBlock\n - DOMAIN-SUFFIX,temp.163.com,AdBlock\n - DOMAIN-SUFFIX,tencentmind.com,AdBlock\n - DOMAIN-SUFFIX,tenddata.com,AdBlock\n - DOMAIN-SUFFIX,test.api.xlmc.sandai.net,AdBlock\n - DOMAIN-SUFFIX,test.eduancm.com,AdBlock\n - DOMAIN-SUFFIX,test.surepush.cn,AdBlock\n - DOMAIN-SUFFIX,textlink.simba.taobao.com,AdBlock\n - DOMAIN-SUFFIX,tf.caohua.com,AdBlock\n - DOMAIN-SUFFIX,tf.hdfdm.com,AdBlock\n - DOMAIN-SUFFIX,tf.hftaili.com,AdBlock\n - DOMAIN-SUFFIX,t-flow.flyme.cn,AdBlock\n - DOMAIN-SUFFIX,tfssl.caohua.com,AdBlock\n - DOMAIN-SUFFIX,tg.1155t.cn,AdBlock\n - DOMAIN-SUFFIX,tg.52digua.com,AdBlock\n - DOMAIN-SUFFIX,tg.jifen.2345.com,AdBlock\n - DOMAIN-SUFFIX,tg.m.37.com,AdBlock\n - DOMAIN-SUFFIX,tga.csbew.com,AdBlock\n - DOMAIN-SUFFIX,tgb.csbew.com,AdBlock\n - DOMAIN-SUFFIX,th21333.com,AdBlock\n - DOMAIN-SUFFIX,th7.cn,AdBlock\n - DOMAIN-SUFFIX,thejesperbay.com,AdBlock\n - DOMAIN-SUFFIX,themis.yahoo.com,AdBlock\n - DOMAIN-SUFFIX,thescenseproject.com,AdBlock\n - DOMAIN-SUFFIX,thetestpage.39.net,AdBlock\n - DOMAIN-SUFFIX,thoughtleadr.com,AdBlock\n - DOMAIN-SUFFIX,thxnr.com,AdBlock\n - DOMAIN-SUFFIX,thyvjboy.com,AdBlock\n - DOMAIN-SUFFIX,thztv.net,AdBlock\n - DOMAIN-SUFFIX,ti.tradetracker.net,AdBlock\n - DOMAIN-SUFFIX,tiads.time.com,AdBlock\n - DOMAIN-SUFFIX,tiangoutai.com,AdBlock\n - DOMAIN-SUFFIX,tiangu99.com,AdBlock\n - DOMAIN-SUFFIX,tianmidian.com,AdBlock\n - DOMAIN-SUFFIX,tianqi777.com,AdBlock\n - DOMAIN-SUFFIX,tianyanzs.com,AdBlock\n - DOMAIN-SUFFIX,ticcdn.com,AdBlock\n - DOMAIN-SUFFIX,timelog.moviebox.baofeng.com,AdBlock\n - DOMAIN-SUFFIX,tiqcdn.com,AdBlock\n - DOMAIN-SUFFIX,titan.babytree.com,AdBlock\n - DOMAIN-SUFFIX,titan.guestworld.tripod.lycos.com,AdBlock\n - DOMAIN-SUFFIX,titan01.babytree.com,AdBlock\n - DOMAIN-SUFFIX,titi.qifajiang.cn,AdBlock\n - DOMAIN-SUFFIX,tjf.lyhuayun.com,AdBlock\n - DOMAIN-SUFFIX,tjhuajiantang.com,AdBlock\n - DOMAIN-SUFFIX,tjlog.easou.com,AdBlock\n - DOMAIN-SUFFIX,tjlog.ps.easou.com,AdBlock\n - DOMAIN-SUFFIX,tjqonline.cn,AdBlock\n - DOMAIN-SUFFIX,tjs.sjs.sinajs.cn,AdBlock\n - DOMAIN-SUFFIX,tk.baidu.com,AdBlock\n - DOMAIN-SUFFIX,tk.optaim.com,AdBlock\n - DOMAIN-SUFFIX,tkd777.cn,AdBlock\n - DOMAIN-SUFFIX,tkmdng.cn,AdBlock\n - DOMAIN-SUFFIX,tkweb.baidu.com,AdBlock\n - DOMAIN-SUFFIX,t-l.play.aiseet.atianqi.com,AdBlock\n - DOMAIN-SUFFIX,tmcs.net,AdBlock\n - DOMAIN-SUFFIX,tmisc.home.news.cn,AdBlock\n - DOMAIN-SUFFIX,tns-counter.ru,AdBlock\n - DOMAIN-SUFFIX,token.rubiconproject.com,AdBlock\n - DOMAIN-SUFFIX,tongji-res1.meizu.com,AdBlock\n - DOMAIN-SUFFIX,tongqing2015.com,AdBlock\n - DOMAIN-SUFFIX,tool.btrabbit.la,AdBlock\n - DOMAIN-SUFFIX,toolbar.baidu.com,AdBlock\n - DOMAIN-SUFFIX,toolbar.msn.com,AdBlock\n - DOMAIN-SUFFIX,toourbb.com,AdBlock\n - DOMAIN-SUFFIX,top.h.qhimg.com,AdBlock\n - DOMAIN-SUFFIX,top.h.qhmsg.com,AdBlock\n - DOMAIN-SUFFIX,top267.com,AdBlock\n - DOMAIN-SUFFIX,topitme.com,AdBlock\n - DOMAIN-SUFFIX,total.xinmin.cn,AdBlock\n - DOMAIN-SUFFIX,touclick.com,AdBlock\n - DOMAIN-SUFFIX,toutiao.2haha.com,AdBlock\n - DOMAIN-SUFFIX,toutiao.jxnews.com.cn,AdBlock\n - DOMAIN-SUFFIX,tp.sgcn.com,AdBlock\n - DOMAIN-SUFFIX,tpe163.com,AdBlock\n - DOMAIN-SUFFIX,tpush.html5.qq.com,AdBlock\n - DOMAIN-SUFFIX,tqd.ntpddq.com,AdBlock\n - DOMAIN-SUFFIX,track-east.mobileadtrading.com,AdBlock\n - DOMAIN-SUFFIX,trackersimulator.org,AdBlock\n - DOMAIN-SUFFIX,tracking-server-prod-1.zenmxapps.com,AdBlock\n - DOMAIN-SUFFIX,tradeadexchange.com,AdBlock\n - DOMAIN-SUFFIX,tradeccl.com,AdBlock\n - DOMAIN-SUFFIX,trafficfactory.biz,AdBlock\n - DOMAIN-SUFFIX,trafficjam.cn,AdBlock\n - DOMAIN-SUFFIX,trafficjunky.com,AdBlock\n - DOMAIN-SUFFIX,trafficjunky.net,AdBlock\n - DOMAIN-SUFFIX,trafficmp.com,AdBlock\n - DOMAIN-SUFFIX,tralog.ganji.com,AdBlock\n - DOMAIN-SUFFIX,tran.news.so.com,AdBlock\n - DOMAIN-SUFFIX,tredman.com,AdBlock\n - DOMAIN-SUFFIX,trends.mobile.sina.cn,AdBlock\n - DOMAIN-SUFFIX,trial.alcohol-soft.com,AdBlock\n - DOMAIN-SUFFIX,trwba.com,AdBlock\n - DOMAIN-SUFFIX,trzina.com,AdBlock\n - DOMAIN-SUFFIX,ts.hivecn.cn,AdBlock\n - DOMAIN-SUFFIX,tsdlp.com,AdBlock\n - DOMAIN-SUFFIX,tsjdgzm.m.3dllc.cc,AdBlock\n - DOMAIN-SUFFIX,tsrc8.com,AdBlock\n - DOMAIN-SUFFIX,tt.biquge.la,AdBlock\n - DOMAIN-SUFFIX,tt.shxinjie.cn,AdBlock\n - DOMAIN-SUFFIX,tt.twzui6.com,AdBlock\n - DOMAIN-SUFFIX,tt123.eastday.com,AdBlock\n - DOMAIN-SUFFIX,tt321.eastday.com,AdBlock\n - DOMAIN-SUFFIX,ttcdn.cn,AdBlock\n - DOMAIN-SUFFIX,ttlm.cc,AdBlock\n - DOMAIN-SUFFIX,ttlowe.com,AdBlock\n - DOMAIN-SUFFIX,ttm.htfmbt.com,AdBlock\n - DOMAIN-SUFFIX,ttts.leztc.com,AdBlock\n - DOMAIN-SUFFIX,ttts.miyue17.com,AdBlock\n - DOMAIN-SUFFIX,tu.baixing.com,AdBlock\n - DOMAIN-SUFFIX,tu.njflfd.com,AdBlock\n - DOMAIN-SUFFIX,tu.szefe.com,AdBlock\n - DOMAIN-SUFFIX,tuadong.com,AdBlock\n - DOMAIN-SUFFIX,tuanxue360.net,AdBlock\n - DOMAIN-SUFFIX,tui.gtimg.com,AdBlock\n - DOMAIN-SUFFIX,tui1999.com,AdBlock\n - DOMAIN-SUFFIX,tui98.cn,AdBlock\n - DOMAIN-SUFFIX,tuia.cn,AdBlock\n - DOMAIN-SUFFIX,tuidang.epochtimes.org,AdBlock\n - DOMAIN-SUFFIX,tuidang.org,AdBlock\n - DOMAIN-SUFFIX,tuigoo.com,AdBlock\n - DOMAIN-SUFFIX,tuiguang.178.com,AdBlock\n - DOMAIN-SUFFIX,tuiguang.meitu.com,AdBlock\n - DOMAIN-SUFFIX,tuiguang.yicha.cn,AdBlock\n - DOMAIN-SUFFIX,tuijian.baidu.com,AdBlock\n - DOMAIN-SUFFIX,tuipenguin.com,AdBlock\n - DOMAIN-SUFFIX,tuisong.baidu.com,AdBlock\n - DOMAIN-SUFFIX,tuitiger.com,AdBlock\n - DOMAIN-SUFFIX,tuituigui19999.com,AdBlock\n - DOMAIN-SUFFIX,tujidao.com,AdBlock\n - DOMAIN-SUFFIX,tukeai.com,AdBlock\n - DOMAIN-SUFFIX,tukexiu.com,AdBlock\n - DOMAIN-SUFFIX,tukj.net,AdBlock\n - DOMAIN-SUFFIX,tumblrprobes.cedexis.com,AdBlock\n - DOMAIN-SUFFIX,tumblrreports.cedexis.com,AdBlock\n - DOMAIN-SUFFIX,tunion-api.m.taobao.com,AdBlock\n - DOMAIN-SUFFIX,turn.com,AdBlock\n - DOMAIN-SUFFIX,tv.code.jjyx.com,AdBlock\n - DOMAIN-SUFFIX,tw.adon.vpon.com,AdBlock\n - DOMAIN-SUFFIX,tw.adx.nextmedia.com,AdBlock\n - DOMAIN-SUFFIX,tw.api.vpon.com,AdBlock\n - DOMAIN-SUFFIX,tw.fgmtv.org,AdBlock\n - DOMAIN-SUFFIX,tw.pub.vpon.com,AdBlock\n - DOMAIN-SUFFIX,tw13b093.sandai.net,AdBlock\n - DOMAIN-SUFFIX,twb98.com,AdBlock\n - DOMAIN-SUFFIX,twcczhu.com,AdBlock\n - DOMAIN-SUFFIX,twh5.com,AdBlock\n - DOMAIN-SUFFIX,twinplan.com,AdBlock\n - DOMAIN-SUFFIX,twitterzs.com,AdBlock\n - DOMAIN-SUFFIX,twldmx.com,AdBlock\n - DOMAIN-SUFFIX,twzui6.com,AdBlock\n - DOMAIN-SUFFIX,tx.lwinl.com,AdBlock\n - DOMAIN-SUFFIX,txt.go.sohu.com,AdBlock\n - DOMAIN-SUFFIX,txtad.jijiplayer.com,AdBlock\n - DOMAIN-SUFFIX,tylll.com,AdBlock\n - DOMAIN-SUFFIX,tyu.quanliyouxi.cn,AdBlock\n - DOMAIN-SUFFIX,tyx.xtzxmy.com,AdBlock\n - DOMAIN-SUFFIX,tz.1688988.com,AdBlock\n - DOMAIN-SUFFIX,tz.zjhoudao.com,AdBlock\n - DOMAIN-SUFFIX,tzbtw.com,AdBlock\n - DOMAIN-SUFFIX,tz-dsp.com,AdBlock\n - DOMAIN-SUFFIX,u.63kc.com,AdBlock\n - DOMAIN-SUFFIX,u.cnzol.com,AdBlock\n - DOMAIN-SUFFIX,u.ddvip.com,AdBlock\n - DOMAIN-SUFFIX,u.diannaodian.com,AdBlock\n - DOMAIN-SUFFIX,u.huoying666.com,AdBlock\n - DOMAIN-SUFFIX,u.jimdo.com,AdBlock\n - DOMAIN-SUFFIX,u.qijipc.com,AdBlock\n - DOMAIN-SUFFIX,u.raidmedia.com.cn,AdBlock\n - DOMAIN-SUFFIX,u.uc123.com,AdBlock\n - DOMAIN-SUFFIX,u.ucfly.com,AdBlock\n - DOMAIN-SUFFIX,u.xcy8.com,AdBlock\n - DOMAIN-SUFFIX,u.yiiwoo.com,AdBlock\n - DOMAIN-SUFFIX,u.yizuya.com,AdBlock\n - DOMAIN-SUFFIX,u0.s.minisplat.cn,AdBlock\n - DOMAIN-SUFFIX,u034024.nr1234.com,AdBlock\n - DOMAIN-SUFFIX,u1.img.mobile.sina.cn,AdBlock\n - DOMAIN-SUFFIX,u1.s.minisplat.cn,AdBlock\n - DOMAIN-SUFFIX,u1.shuaiku.com,AdBlock\n - DOMAIN-SUFFIX,u2.s.minisplat.cn,AdBlock\n - DOMAIN-SUFFIX,u291014.nr1234.com,AdBlock\n - DOMAIN-SUFFIX,u349036.ff112222.com,AdBlock\n - DOMAIN-SUFFIX,ua.badongo.com,AdBlock\n - DOMAIN-SUFFIX,uapi.punchbox.org,AdBlock\n - DOMAIN-SUFFIX,ubm.fangtoo.com,AdBlock\n - DOMAIN-SUFFIX,uc.haoyunyuan.cc,AdBlock\n - DOMAIN-SUFFIX,uc.xiansuper.com,AdBlock\n - DOMAIN-SUFFIX,uc2.atobo.com.cn,AdBlock\n - DOMAIN-SUFFIX,uc610.com,AdBlock\n - DOMAIN-SUFFIX,uc9.ucweb.com,AdBlock\n - DOMAIN-SUFFIX,ucaliyun.cn,AdBlock\n - DOMAIN-SUFFIX,ucan.25pp.com,AdBlock\n - DOMAIN-SUFFIX,ucqq.cnsptv.com.cn,AdBlock\n - DOMAIN-SUFFIX,ucrzgcs.cn,AdBlock\n - DOMAIN-SUFFIX,ucstat.baidu.com,AdBlock\n - DOMAIN-SUFFIX,ucus.ucweb.com,AdBlock\n - DOMAIN-SUFFIX,ucxxii.com,AdBlock\n - DOMAIN-SUFFIX,uczzd.com,AdBlock\n - DOMAIN-SUFFIX,uczzd.com.cn,AdBlock\n - DOMAIN-SUFFIX,uczzd.net,AdBlock\n - DOMAIN-SUFFIX,udata.mixmarket.biz,AdBlock\n - DOMAIN-SUFFIX,udc.msn.com,AdBlock\n - DOMAIN-SUFFIX,udm.scorecardresearch.com,AdBlock\n - DOMAIN-SUFFIX,udrig.com,AdBlock\n - DOMAIN-SUFFIX,udrwyjpwjfeg.com,AdBlock\n - DOMAIN-SUFFIX,ue.ueadlian.com,AdBlock\n - DOMAIN-SUFFIX,ue.yeyoucdn.com,AdBlock\n - DOMAIN-SUFFIX,ueadlian.com,AdBlock\n - DOMAIN-SUFFIX,uebawtz7.me,AdBlock\n - DOMAIN-SUFFIX,ugc.moji001.com,AdBlock\n - DOMAIN-SUFFIX,ugg.keefung-zs.com,AdBlock\n - DOMAIN-SUFFIX,ugg66.com,AdBlock\n - DOMAIN-SUFFIX,ugvip.com,AdBlock\n - DOMAIN-SUFFIX,ui37.net,AdBlock\n - DOMAIN-SUFFIX,uid.ksosoft.com,AdBlock\n - DOMAIN-SUFFIX,uid.mdbchina.com,AdBlock\n - DOMAIN-SUFFIX,uimg.27admin.com,AdBlock\n - DOMAIN-SUFFIX,uimserv.net,AdBlock\n - DOMAIN-SUFFIX,ujian.cc,AdBlock\n - DOMAIN-SUFFIX,ujikdd041o.cn,AdBlock\n - DOMAIN-SUFFIX,uk3oi.adgze.cn,AdBlock\n - DOMAIN-SUFFIX,ukeiae.com,AdBlock\n - DOMAIN-SUFFIX,ulic.baidu.com,AdBlock\n - DOMAIN-SUFFIX,ulink.cc,AdBlock\n - DOMAIN-SUFFIX,ultraiso.net,AdBlock\n - DOMAIN-SUFFIX,um.simpli.fi,AdBlock\n - DOMAIN-SUFFIX,um0592.com,AdBlock\n - DOMAIN-SUFFIX,um2.eqads.com,AdBlock\n - DOMAIN-SUFFIX,um29.com,AdBlock\n - DOMAIN-SUFFIX,umid.orion.meizu.com,AdBlock\n - DOMAIN-SUFFIX,umyai.com,AdBlock\n - DOMAIN-SUFFIX,un.52rkl.cn,AdBlock\n - DOMAIN-SUFFIX,un.soarfi.cn,AdBlock\n - DOMAIN-SUFFIX,un.winasdaq.com,AdBlock\n - DOMAIN-SUFFIX,un1.takefoto.cn,AdBlock\n - DOMAIN-SUFFIX,unconf.mobad.ijinshan.com,AdBlock\n - DOMAIN-SUFFIX,undm.qibulo.com,AdBlock\n - DOMAIN-SUFFIX,unicast.ign.com,AdBlock\n - DOMAIN-SUFFIX,unicast.msn.com,AdBlock\n - DOMAIN-SUFFIX,unilog.wostore.cn,AdBlock\n - DOMAIN-SUFFIX,unimhk.com,AdBlock\n - DOMAIN-SUFFIX,union.baidu.com,AdBlock\n - DOMAIN-SUFFIX,union.baidustatic.guannin.com,AdBlock\n - DOMAIN-SUFFIX,union.china.com.cn,AdBlock\n - DOMAIN-SUFFIX,union.dbba.cn,AdBlock\n - DOMAIN-SUFFIX,union.maccms.com,AdBlock\n - DOMAIN-SUFFIX,union.mop.com,AdBlock\n - DOMAIN-SUFFIX,union.sogou.com,AdBlock\n - DOMAIN-SUFFIX,union.star-media.cn,AdBlock\n - DOMAIN-SUFFIX,union.youdao.com,AdBlock\n - DOMAIN-SUFFIX,union1.xiaojianjian.net,AdBlock\n - DOMAIN-SUFFIX,uniondm.cz88.net,AdBlock\n - DOMAIN-SUFFIX,unionimage.baidu.com,AdBlock\n - DOMAIN-SUFFIX,unionsy.com,AdBlock\n - DOMAIN-SUFFIX,union-wifi.com,AdBlock\n - DOMAIN-SUFFIX,unipaydl.wostore.cn,AdBlock\n - DOMAIN-SUFFIX,unipayupg.wostore.cn,AdBlock\n - DOMAIN-SUFFIX,unitacs.m.taobao.com,AdBlock\n - DOMAIN-SUFFIX,unjs.jfcdns.com,AdBlock\n - DOMAIN-SUFFIX,unlitui.com,AdBlock\n - DOMAIN-SUFFIX,uns.soarfi.cn,AdBlock\n - DOMAIN-SUFFIX,untitled.dwstatic.com,AdBlock\n - DOMAIN-SUFFIX,uodoo.com,AdBlock\n - DOMAIN-SUFFIX,uoyrsd.com,AdBlock\n - DOMAIN-SUFFIX,up.cm.ksmobile.com,AdBlock\n - DOMAIN-SUFFIX,up.hiao.com,AdBlock\n - DOMAIN-SUFFIX,up4.ucweb.com,AdBlock\n - DOMAIN-SUFFIX,upd.faronicslabs.com,AdBlock\n - DOMAIN-SUFFIX,update.360safe.com,AdBlock\n - DOMAIN-SUFFIX,update.avlyun.sec.miui.com,AdBlock\n - DOMAIN-SUFFIX,update.bainv.net,AdBlock\n - DOMAIN-SUFFIX,update.coolyun.com,AdBlock\n - DOMAIN-SUFFIX,update.juw37xqo3x.com,AdBlock\n - DOMAIN-SUFFIX,update.minipage.2345.com,AdBlock\n - DOMAIN-SUFFIX,update.mobile.kugou.com,AdBlock\n - DOMAIN-SUFFIX,update.sdk.jiguang.cn,AdBlock\n - DOMAIN-SUFFIX,updatecenter.qq.com,AdBlock\n - DOMAIN-SUFFIX,updatepage.kuwo.cn,AdBlock\n - DOMAIN-SUFFIX,updates-s3.binaryage.com,AdBlock\n - DOMAIN-SUFFIX,uplze.code.weddingeeos.com,AdBlock\n - DOMAIN-SUFFIX,ups.ksmobile.net,AdBlock\n - DOMAIN-SUFFIX,upush.res.meizu.com,AdBlock\n - DOMAIN-SUFFIX,uqszvk.code.weddingeeos.com,AdBlock\n - DOMAIN-SUFFIX,uqum.52shouyou.com.cn,AdBlock\n - DOMAIN-SUFFIX,urbanairship.com,AdBlock\n - DOMAIN-SUFFIX,urchin.5173.com,AdBlock\n - DOMAIN-SUFFIX,urh.tylll.com,AdBlock\n - DOMAIN-SUFFIX,urhu.cn,AdBlock\n - DOMAIN-SUFFIX,uri6.com,AdBlock\n - DOMAIN-SUFFIX,url.222bz.com,AdBlock\n - DOMAIN-SUFFIX,url.tudown.com,AdBlock\n - DOMAIN-SUFFIX,urls.api.twitter.com,AdBlock\n - DOMAIN-SUFFIX,us.bannyat.com,AdBlock\n - DOMAIN-SUFFIX,us.bs.serving-sys.com,AdBlock\n - DOMAIN-SUFFIX,user.tiankongzudui.com,AdBlock\n - DOMAIN-SUFFIX,usercollection.chinadaily.com.cn,AdBlock\n - DOMAIN-SUFFIX,ushaqi.com,AdBlock\n - DOMAIN-SUFFIX,usingde.com,AdBlock\n - DOMAIN-SUFFIX,usr.mgid.com,AdBlock\n - DOMAIN-SUFFIX,uss-pid.lenovomm.com,AdBlock\n - DOMAIN-SUFFIX,usync.aws.rubiconproject.com,AdBlock\n - DOMAIN-SUFFIX,ut2.shuqistat.com,AdBlock\n - DOMAIN-SUFFIX,util.nphoto.net,AdBlock\n - DOMAIN-SUFFIX,utility.baidu.com,AdBlock\n - DOMAIN-SUFFIX,utility.rogersmedia.com,AdBlock\n - DOMAIN-SUFFIX,utk.baidu.com,AdBlock\n - DOMAIN-SUFFIX,utp.ucweb.com,AdBlock\n - DOMAIN-SUFFIX,uu.feipukeplus.com,AdBlock\n - DOMAIN-SUFFIX,uu.zeverdg.com,AdBlock\n - DOMAIN-SUFFIX,uuidksinc.net,AdBlock\n - DOMAIN-SUFFIX,uulucky.com,AdBlock\n - DOMAIN-SUFFIX,uvclick.com,AdBlock\n - DOMAIN-SUFFIX,uw9377.com,AdBlock\n - DOMAIN-SUFFIX,uxip.meizu.com,AdBlock\n - DOMAIN-SUFFIX,uyunad.com,AdBlock\n - DOMAIN-SUFFIX,uzpmrbek.com,AdBlock\n - DOMAIN-SUFFIX,v.dbncp.com,AdBlock\n - DOMAIN-SUFFIX,v.e7002.com,AdBlock\n - DOMAIN-SUFFIX,v.irs01.com,AdBlock\n - DOMAIN-SUFFIX,v.oq68.com,AdBlock\n - DOMAIN-SUFFIX,v.rmbn.net,AdBlock\n - DOMAIN-SUFFIX,v.szpaopao.com,AdBlock\n - DOMAIN-SUFFIX,v00087.com,AdBlock\n - DOMAIN-SUFFIX,v02u9.cn,AdBlock\n - DOMAIN-SUFFIX,v1.0594529.com,AdBlock\n - DOMAIN-SUFFIX,v1.ujian.cc,AdBlock\n - DOMAIN-SUFFIX,v12-r0566gbscjw.z.irs01.com,AdBlock\n - DOMAIN-SUFFIX,v1-feed.idreamsky.com,AdBlock\n - DOMAIN-SUFFIX,v2.fm.n.duokanbox.com,AdBlock\n - DOMAIN-SUFFIX,v2.jiathis.com,AdBlock\n - DOMAIN-SUFFIX,v3.jiathis.com,AdBlock\n - DOMAIN-SUFFIX,v66v66.com,AdBlock\n - DOMAIN-SUFFIX,v7.kawinhome.com,AdBlock\n - DOMAIN-SUFFIX,v707070.com,AdBlock\n - DOMAIN-SUFFIX,va.gxpan.cn,AdBlock\n - DOMAIN-SUFFIX,vad1.jianshen8.com,AdBlock\n - DOMAIN-SUFFIX,val.atm.cp31.ott.cibntv.net,AdBlock\n - DOMAIN-SUFFIX,valf.atm.cp31.ott.cibntv.net,AdBlock\n - DOMAIN-SUFFIX,vamaker.com,AdBlock\n - DOMAIN-SUFFIX,vangmobi.com,AdBlock\n - DOMAIN-SUFFIX,vas.funshion.com,AdBlock\n - DOMAIN-SUFFIX,vatrack.hinet.net,AdBlock\n - DOMAIN-SUFFIX,vcfs6ip5h6.bid,AdBlock\n - DOMAIN-SUFFIX,vda.17173.com,AdBlock\n - DOMAIN-SUFFIX,vdapprecv.app.cntvwb.cn,AdBlock\n - DOMAIN-SUFFIX,vdazz.net,AdBlock\n - DOMAIN-SUFFIX,ve.tsdlp.com,AdBlock\n - DOMAIN-SUFFIX,vedeh.com,AdBlock\n - DOMAIN-SUFFIX,vegaschina.cn,AdBlock\n - DOMAIN-SUFFIX,vegent.cn,AdBlock\n - DOMAIN-SUFFIX,vendor1.fitschigogerl.com,AdBlock\n - DOMAIN-SUFFIX,ver.touclick.com,AdBlock\n - DOMAIN-SUFFIX,verdict.abc.go.com,AdBlock\n - DOMAIN-SUFFIX,vers80.com,AdBlock\n - DOMAIN-SUFFIX,vg02h8z1ul.me,AdBlock\n - DOMAIN-SUFFIX,vi0.mzy2014.com,AdBlock\n - DOMAIN-SUFFIX,vi1.ku6img.net,AdBlock\n - DOMAIN-SUFFIX,vi1.mzy2014.com,AdBlock\n - DOMAIN-SUFFIX,vi1.souid.com,AdBlock\n - DOMAIN-SUFFIX,vi2.ku6img.net,AdBlock\n - DOMAIN-SUFFIX,vichc.com,AdBlock\n - DOMAIN-SUFFIX,victorjx.com,AdBlock\n - DOMAIN-SUFFIX,video.cooguo.com,AdBlock\n - DOMAIN-SUFFIX,video.ureport.push.qq.com,AdBlock\n - DOMAIN-SUFFIX,video.wap.mpush.qq.com,AdBlock\n - DOMAIN-SUFFIX,videondun.com,AdBlock\n - DOMAIN-SUFFIX,videopush.baidu.com,AdBlock\n - DOMAIN-SUFFIX,viglink.com,AdBlock\n - DOMAIN-SUFFIX,vimg.dwstatic.com,AdBlock\n - DOMAIN-SUFFIX,vip.cainiaofx.com,AdBlock\n - DOMAIN-SUFFIX,vip.hyz86.com,AdBlock\n - DOMAIN-SUFFIX,vip.id528.com,AdBlock\n - DOMAIN-SUFFIX,vip.jindu179.com,AdBlock\n - DOMAIN-SUFFIX,vip.mall044.com,AdBlock\n - DOMAIN-SUFFIX,vip.media8.cn,AdBlock\n - DOMAIN-SUFFIX,vip.pinghuhome.com,AdBlock\n - DOMAIN-SUFFIX,vip.qqxwf.com,AdBlock\n - DOMAIN-SUFFIX,vip.zhuba8.com,AdBlock\n - DOMAIN-SUFFIX,vipads.cn,AdBlock\n - DOMAIN-SUFFIX,vista.tgbus.com,AdBlock\n - DOMAIN-SUFFIX,vista.tgbusdata.cn,AdBlock\n - DOMAIN-SUFFIX,visualscience.external.bbc.co.uk,AdBlock\n - DOMAIN-SUFFIX,vj.x-ssp.com,AdBlock\n - DOMAIN-SUFFIX,vj0.42422277.com,AdBlock\n - DOMAIN-SUFFIX,vjcyehtqm9.me,AdBlock\n - DOMAIN-SUFFIX,vl8c4g7tmo.me,AdBlock\n - DOMAIN-SUFFIX,vlive.qqvideo.tc.qq.com,AdBlock\n - DOMAIN-SUFFIX,vmzqwz.cn,AdBlock\n - DOMAIN-SUFFIX,vn543.com,AdBlock\n - DOMAIN-SUFFIX,vns800600.net,AdBlock\n - DOMAIN-SUFFIX,vodlog.m1905.cn,AdBlock\n - DOMAIN-SUFFIX,voiceads.cn,AdBlock\n - DOMAIN-SUFFIX,voiceads.com,AdBlock\n - DOMAIN-SUFFIX,voila.refr.adgtw.orangeads.fr,AdBlock\n - DOMAIN-SUFFIX,vol.lflili.com,AdBlock\n - DOMAIN-SUFFIX,vpon.com,AdBlock\n - DOMAIN-SUFFIX,vps.inte.sogou.com,AdBlock\n - DOMAIN-SUFFIX,vs.funshion.com,AdBlock\n - DOMAIN-SUFFIX,vs19.gzcu.u3.ucweb.com,AdBlock\n - DOMAIN-SUFFIX,vs2.gzcu.u3.ucweb.com,AdBlock\n - DOMAIN-SUFFIX,vs7.gzcu.u3.ucweb.com,AdBlock\n - DOMAIN-SUFFIX,vs8.gzct.u3.ucweb.com,AdBlock\n - DOMAIN-SUFFIX,vs8.gzcu.u3.ucweb.com,AdBlock\n - DOMAIN-SUFFIX,v-sence.gentags.net,AdBlock\n - DOMAIN-SUFFIX,vsnoon.com,AdBlock\n - DOMAIN-SUFFIX,vt.bjhdonline.com,AdBlock\n - DOMAIN-SUFFIX,vtale.org,AdBlock\n - DOMAIN-SUFFIX,vungle.cn,AdBlock\n - DOMAIN-SUFFIX,vungle.com,AdBlock\n - DOMAIN-SUFFIX,vupload.duowan.com,AdBlock\n - DOMAIN-SUFFIX,vvlog.moviebox.baofeng.com,AdBlock\n - DOMAIN-SUFFIX,vvv.ieduw.com,AdBlock\n - DOMAIN-SUFFIX,vvvulqn7.com,AdBlock\n - DOMAIN-SUFFIX,vwkhdi.cn,AdBlock\n - DOMAIN-SUFFIX,vwws6.net,AdBlock\n - DOMAIN-SUFFIX,vz-cdn.contentabc.com,AdBlock\n - DOMAIN-SUFFIX,vz-cdn.trafficjunky.net,AdBlock\n - DOMAIN-SUFFIX,w.bobocn.cn,AdBlock\n - DOMAIN-SUFFIX,w.cube3d.cn,AdBlock\n - DOMAIN-SUFFIX,w.gdown.baidu.com,AdBlock\n - DOMAIN-SUFFIX,w.homes.yahoo.net,AdBlock\n - DOMAIN-SUFFIX,w.jscsd.cn,AdBlock\n - DOMAIN-SUFFIX,w.m.taobao.com,AdBlock\n - DOMAIN-SUFFIX,w.punchbox.org,AdBlock\n - DOMAIN-SUFFIX,w.sharethis.com,AdBlock\n - DOMAIN-SUFFIX,w.waacorp.com,AdBlock\n - DOMAIN-SUFFIX,w.werpig.com,AdBlock\n - DOMAIN-SUFFIX,w.x.baidu.com,AdBlock\n - DOMAIN-SUFFIX,w.xiaopiaoyou.com,AdBlock\n - DOMAIN-SUFFIX,w.yamaidei.cn,AdBlock\n - DOMAIN-SUFFIX,w.yinyuehu.cn,AdBlock\n - DOMAIN-SUFFIX,w.ymapp.com,AdBlock\n - DOMAIN-SUFFIX,w1.diaoyou.com,AdBlock\n - DOMAIN-SUFFIX,w2528.com,AdBlock\n - DOMAIN-SUFFIX,w3.yinyuehu.cn,AdBlock\n - DOMAIN-SUFFIX,w3989.com,AdBlock\n - DOMAIN-SUFFIX,w5sac788c1.360doc.cn,AdBlock\n - DOMAIN-SUFFIX,w6061.move7.com,AdBlock\n - DOMAIN-SUFFIX,w65p.com,AdBlock\n - DOMAIN-SUFFIX,w8.com.cn,AdBlock\n - DOMAIN-SUFFIX,w88.go.com,AdBlock\n - DOMAIN-SUFFIX,wa.kuwo.cn,AdBlock\n - DOMAIN-SUFFIX,wallet.advcash.com,AdBlock\n - DOMAIN-SUFFIX,wan.2345.com,AdBlock\n - DOMAIN-SUFFIX,wan.douyu.com,AdBlock\n - DOMAIN-SUFFIX,wan.rising.cn,AdBlock\n - DOMAIN-SUFFIX,wan.sogou.com,AdBlock\n - DOMAIN-SUFFIX,wancai.com,AdBlock\n - DOMAIN-SUFFIX,wanfeng1.com,AdBlock\n - DOMAIN-SUFFIX,wangdaizao.com,AdBlock\n - DOMAIN-SUFFIX,wangdq.com,AdBlock\n - DOMAIN-SUFFIX,wangmeng.baidu.com,AdBlock\n - DOMAIN-SUFFIX,wangmeng.sogou.com,AdBlock\n - DOMAIN-SUFFIX,wangsufast.com,AdBlock\n - DOMAIN-SUFFIX,wanproxy.127.net,AdBlock\n - DOMAIN-SUFFIX,wantaico.com,AdBlock\n - DOMAIN-SUFFIX,wantfour.com,AdBlock\n - DOMAIN-SUFFIX,wap.114so.cn,AdBlock\n - DOMAIN-SUFFIX,wap.138lm.com,AdBlock\n - DOMAIN-SUFFIX,wap.bytdzsw.com,AdBlock\n - DOMAIN-SUFFIX,wap.cmgame.com,AdBlock\n - DOMAIN-SUFFIX,wap.moad.cn,AdBlock\n - DOMAIN-SUFFIX,wap.mpush.qq.com,AdBlock\n - DOMAIN-SUFFIX,wap.tanwan.com,AdBlock\n - DOMAIN-SUFFIX,wap.txwdn.com,AdBlock\n - DOMAIN-SUFFIX,wap.wooboo.com.cn,AdBlock\n - DOMAIN-SUFFIX,wap001.bytravel.cn,AdBlock\n - DOMAIN-SUFFIX,wap3.ucweb.com,AdBlock\n - DOMAIN-SUFFIX,wapadv.com,AdBlock\n - DOMAIN-SUFFIX,wappv.zol.com.cn,AdBlock\n - DOMAIN-SUFFIX,waps.cn,AdBlock\n - DOMAIN-SUFFIX,wapscdn.wapx.cn,AdBlock\n - DOMAIN-SUFFIX,wapssl.ff113300.com,AdBlock\n - DOMAIN-SUFFIX,wapwbclick.mobile.sina.cn,AdBlock\n - DOMAIN-SUFFIX,wapx.cn,AdBlock\n - DOMAIN-SUFFIX,wapx.com,AdBlock\n - DOMAIN-SUFFIX,watson.live.com,AdBlock\n - DOMAIN-SUFFIX,watson.microsoft.com,AdBlock\n - DOMAIN-SUFFIX,wazero.online,AdBlock\n - DOMAIN-SUFFIX,wb.gtimg.com,AdBlock\n - DOMAIN-SUFFIX,wbapp.mobile.sina.cn,AdBlock\n - DOMAIN-SUFFIX,wbclick.mobile.sina.cn,AdBlock\n - DOMAIN-SUFFIX,wbpctips.mobile.sina.cn,AdBlock\n - DOMAIN-SUFFIX,wbwl.houyi.baofeng.net,AdBlock\n - DOMAIN-SUFFIX,wda.ydt.com.cn,AdBlock\n - DOMAIN-SUFFIX,wd-edge.sharethis.com,AdBlock\n - DOMAIN-SUFFIX,wdgsl.com,AdBlock\n - DOMAIN-SUFFIX,wds.inte.sogoucdn.com,AdBlock\n - DOMAIN-SUFFIX,wdzsb.com.cn,AdBlock\n - DOMAIN-SUFFIX,we.tm,AdBlock\n - DOMAIN-SUFFIX,weareqy.com,AdBlock\n - DOMAIN-SUFFIX,web.900.la,AdBlock\n - DOMAIN-SUFFIX,web.ali213.net,AdBlock\n - DOMAIN-SUFFIX,web.data.pplive.com,AdBlock\n - DOMAIN-SUFFIX,web.houyi.baofeng.net,AdBlock\n - DOMAIN-SUFFIX,web.kuaisouwifi.com,AdBlock\n - DOMAIN-SUFFIX,web.sogou.com,AdBlock\n - DOMAIN-SUFFIX,webd.home.news.cn,AdBlock\n - DOMAIN-SUFFIX,webdissector.com,AdBlock\n - DOMAIN-SUFFIX,webkooo.com,AdBlock\n - DOMAIN-SUFFIX,weblb-wg.gslb.spotify.com,AdBlock\n - DOMAIN-SUFFIX,webmaster.extabit.com,AdBlock\n - DOMAIN-SUFFIX,webmine.cz,AdBlock\n - DOMAIN-SUFFIX,webstat.kuwo.cn,AdBlock\n - DOMAIN-SUFFIX,webstat.ws.126.net,AdBlock\n - DOMAIN-SUFFIX,webterren.com,AdBlock\n - DOMAIN-SUFFIX,webtrends.yccdn.com,AdBlock\n - DOMAIN-SUFFIX,weibomingzi.com,AdBlock\n - DOMAIN-SUFFIX,weiguizhizuo.com,AdBlock\n - DOMAIN-SUFFIX,weiqiqu.cn,AdBlock\n - DOMAIN-SUFFIX,weishi.baidu.com,AdBlock\n - DOMAIN-SUFFIX,weixiangzu.cn,AdBlock\n - DOMAIN-SUFFIX,weixin.renrenying.com,AdBlock\n - DOMAIN-SUFFIX,weixinvip.ren,AdBlock\n - DOMAIN-SUFFIX,weld.iefsf.com,AdBlock\n - DOMAIN-SUFFIX,weld.uunice.com,AdBlock\n - DOMAIN-SUFFIX,weld830.uunice.com,AdBlock\n - DOMAIN-SUFFIX,weldc1.021ye.com,AdBlock\n - DOMAIN-SUFFIX,werpig.com,AdBlock\n - DOMAIN-SUFFIX,weyyae.com,AdBlock\n - DOMAIN-SUFFIX,wgie.0z5jn.cn,AdBlock\n - DOMAIN-SUFFIX,wgnlz.com,AdBlock\n - DOMAIN-SUFFIX,wgnmp.com,AdBlock\n - DOMAIN-SUFFIX,whafwl.com,AdBlock\n - DOMAIN-SUFFIX,whalecloud.com,AdBlock\n - DOMAIN-SUFFIX,whcrdz.com,AdBlock\n - DOMAIN-SUFFIX,whistleout.s3.amazonaws.com,AdBlock\n - DOMAIN-SUFFIX,whn.star-media.cn,AdBlock\n - DOMAIN-SUFFIX,whpxy.com,AdBlock\n - DOMAIN-SUFFIX,whu.cwpush.com,AdBlock\n - DOMAIN-SUFFIX,whytoss.com,AdBlock\n - DOMAIN-SUFFIX,widget.criteo.com,AdBlock\n - DOMAIN-SUFFIX,widget.crowdignite.com,AdBlock\n - DOMAIN-SUFFIX,widget.directory.dailycommercial.com,AdBlock\n - DOMAIN-SUFFIX,widget.kelkoo.com,AdBlock\n - DOMAIN-SUFFIX,widget.raaze.com,AdBlock\n - DOMAIN-SUFFIX,widget.searchschoolsnetwork.com,AdBlock\n - DOMAIN-SUFFIX,widget.shopstyle.com.au,AdBlock\n - DOMAIN-SUFFIX,widget.solarquotes.com.au,AdBlock\n - DOMAIN-SUFFIX,widgets.comcontent.net,AdBlock\n - DOMAIN-SUFFIX,widgets.realestate.com.au,AdBlock\n - DOMAIN-SUFFIX,widnd.dajiadou6.com,AdBlock\n - DOMAIN-SUFFIX,wifiapi01.51y5.net,AdBlock\n - DOMAIN-SUFFIX,wifiapi02.51y5.net,AdBlock\n - DOMAIN-SUFFIX,wifijia.net,AdBlock\n - DOMAIN-SUFFIX,wifishow.ggsafe.com,AdBlock\n - DOMAIN-SUFFIX,wikigifth.com,AdBlock\n - DOMAIN-SUFFIX,winads.cn,AdBlock\n - DOMAIN-SUFFIX,winasdaq.com,AdBlock\n - DOMAIN-SUFFIX,winbaicai.com,AdBlock\n - DOMAIN-SUFFIX,windcdna.com,AdBlock\n - DOMAIN-SUFFIX,winlinebet.ru,AdBlock\n - DOMAIN-SUFFIX,winvestern.com.cn,AdBlock\n - DOMAIN-SUFFIX,wip3.adobe.com,AdBlock\n - DOMAIN-SUFFIX,wisepush.video.baidu.com,AdBlock\n - DOMAIN-SUFFIX,wiyun.com,AdBlock\n - DOMAIN-SUFFIX,wjguc.com,AdBlock\n - DOMAIN-SUFFIX,wka8.com,AdBlock\n - DOMAIN-SUFFIX,wkanc.com,AdBlock\n - DOMAIN-SUFFIX,wl.51taifu.com,AdBlock\n - DOMAIN-SUFFIX,wl.eastlady.cn,AdBlock\n - DOMAIN-SUFFIX,wl.houyi.baofeng.net,AdBlock\n - DOMAIN-SUFFIX,wlkpa.cn,AdBlock\n - DOMAIN-SUFFIX,wlneteller.adsrv.eacdn.com,AdBlock\n - DOMAIN-SUFFIX,wlpinnaclesports.eacdn.com,AdBlock\n - DOMAIN-SUFFIX,wm.20150.net,AdBlock\n - DOMAIN-SUFFIX,wm.69shi.cn,AdBlock\n - DOMAIN-SUFFIX,wm.baidu.com,AdBlock\n - DOMAIN-SUFFIX,wm.lrswl.com,AdBlock\n - DOMAIN-SUFFIX,wm.mipcdn.com,AdBlock\n - DOMAIN-SUFFIX,wmcdn.qtmojo.cn,AdBlock\n - DOMAIN-SUFFIX,wo.iuni.com.cn,AdBlock\n - DOMAIN-SUFFIX,wo685.com,AdBlock\n - DOMAIN-SUFFIX,woaizhongguo.cdn111222.com,AdBlock\n - DOMAIN-SUFFIX,wodhid.com,AdBlock\n - DOMAIN-SUFFIX,wole.us,AdBlock\n - DOMAIN-SUFFIX,womenbaby.com,AdBlock\n - DOMAIN-SUFFIX,womenwan.com,AdBlock\n - DOMAIN-SUFFIX,wooboo.com.cn,AdBlock\n - DOMAIN-SUFFIX,woocall.sina.com.cn,AdBlock\n - DOMAIN-SUFFIX,woodpecker.uc.cn,AdBlock\n - DOMAIN-SUFFIX,worldh5.gamehz.cn,AdBlock\n - DOMAIN-SUFFIX,wowips.com,AdBlock\n - DOMAIN-SUFFIX,wpc.32df9.rhocdn.net,AdBlock\n - DOMAIN-SUFFIX,wpwdf.com,AdBlock\n - DOMAIN-SUFFIX,wqmobile.com,AdBlock\n - DOMAIN-SUFFIX,wqqsa.puzihua.com,AdBlock\n - DOMAIN-SUFFIX,wqsph.net,AdBlock\n - DOMAIN-SUFFIX,wrvdmh.cn,AdBlock\n - DOMAIN-SUFFIX,ws.ksmobile.net,AdBlock\n - DOMAIN-SUFFIX,ws.progrss.yahoo.com,AdBlock\n - DOMAIN-SUFFIX,ws.sj.qq.com,AdBlock\n - DOMAIN-SUFFIX,ws.tapjoyads.com,AdBlock\n - DOMAIN-SUFFIX,ws.voiceads.cn,AdBlock\n - DOMAIN-SUFFIX,ws1.datouniao.com,AdBlock\n - DOMAIN-SUFFIX,ws2.cootekservice.com,AdBlock\n - DOMAIN-SUFFIX,ws2.datouniao.com,AdBlock\n - DOMAIN-SUFFIX,ws341.com,AdBlock\n - DOMAIN-SUFFIX,ws7j.com,AdBlock\n - DOMAIN-SUFFIX,wshufa.com,AdBlock\n - DOMAIN-SUFFIX,wsoe.kwiago.com,AdBlock\n - DOMAIN-SUFFIX,wsp.marketgid.com,AdBlock\n - DOMAIN-SUFFIX,wstztt.com,AdBlock\n - DOMAIN-SUFFIX,wtcpm.com,AdBlock\n - DOMAIN-SUFFIX,wth.lenovomm.com,AdBlock\n - DOMAIN-SUFFIX,wtpn.twenga.co.uk,AdBlock\n - DOMAIN-SUFFIX,wtpn.twenga.de,AdBlock\n - DOMAIN-SUFFIX,wtrace.cmgame.com,AdBlock\n - DOMAIN-SUFFIX,wu65.com,AdBlock\n - DOMAIN-SUFFIX,wudang05.com,AdBlock\n - DOMAIN-SUFFIX,wuliao.epro.sogou.com,AdBlock\n - DOMAIN-SUFFIX,wuliao.ganji.cn,AdBlock\n - DOMAIN-SUFFIX,wuliao.juqingba.cn,AdBlock\n - DOMAIN-SUFFIX,wumii.cn,AdBlock\n - DOMAIN-SUFFIX,wumii.com,AdBlock\n - DOMAIN-SUFFIX,wuqdebjfhjas.bid,AdBlock\n - DOMAIN-SUFFIX,wuwho.cn,AdBlock\n - DOMAIN-SUFFIX,ww.xiaopiaoyou.com,AdBlock\n - DOMAIN-SUFFIX,ww10.onetad.com,AdBlock\n - DOMAIN-SUFFIX,ww101.onetad.com,AdBlock\n - DOMAIN-SUFFIX,ww11.onetad.com,AdBlock\n - DOMAIN-SUFFIX,ww12.onetad.com,AdBlock\n - DOMAIN-SUFFIX,ww13.onetad.com,AdBlock\n - DOMAIN-SUFFIX,ww202.keyyou.net,AdBlock\n - DOMAIN-SUFFIX,ww202.onetad.com,AdBlock\n - DOMAIN-SUFFIX,ww34.onetad.com,AdBlock\n - DOMAIN-SUFFIX,ww346.onetad.com,AdBlock\n - DOMAIN-SUFFIX,ww360.onetad.com,AdBlock\n - DOMAIN-SUFFIX,ww363.onetad.com,AdBlock\n - DOMAIN-SUFFIX,ww366.onetad.com,AdBlock\n - DOMAIN-SUFFIX,ww78.onetad.com,AdBlock\n - DOMAIN-SUFFIX,ww8.onetad.com,AdBlock\n - DOMAIN-SUFFIX,ww9.onetad.com,AdBlock\n - DOMAIN-SUFFIX,wwis-dubc1-vip60.adobe.com,AdBlock\n - DOMAIN-SUFFIX,wwv.onetad.com,AdBlock\n - DOMAIN-SUFFIX,www2.xinmin.cn,AdBlock\n - DOMAIN-SUFFIX,www-777563.com,AdBlock\n - DOMAIN-SUFFIX,www8.xitek.com,AdBlock\n - DOMAIN-SUFFIX,www9.effectivemeasure.net,AdBlock\n - DOMAIN-SUFFIX,www9.enet.com.cn,AdBlock\n - DOMAIN-SUFFIX,www91.intel.com,AdBlock\n - DOMAIN-SUFFIX,wwwokzyzy.com,AdBlock\n - DOMAIN-SUFFIX,wwww.495495.com,AdBlock\n - DOMAIN-SUFFIX,wwww.551144.com,AdBlock\n - DOMAIN-SUFFIX,wwww.640640.com,AdBlock\n - DOMAIN-SUFFIX,wwww.649649.com,AdBlock\n - DOMAIN-SUFFIX,wx.houyi.baofeng.net,AdBlock\n - DOMAIN-SUFFIX,wx.paigu.com,AdBlock\n - DOMAIN-SUFFIX,wx.xwjqr.com,AdBlock\n - DOMAIN-SUFFIX,wx16999.com,AdBlock\n - DOMAIN-SUFFIX,wxaw.tiantongmaoyi.com,AdBlock\n - DOMAIN-SUFFIX,wxb.wxbdfm.com,AdBlock\n - DOMAIN-SUFFIX,wxmmh.net,AdBlock\n - DOMAIN-SUFFIX,wxsnsdy.tc.qq.com,AdBlock\n - DOMAIN-SUFFIX,wxsnsdy.video.qq.com,AdBlock\n - DOMAIN-SUFFIX,wxsnsdythumb.wxs.qq.com,AdBlock\n - DOMAIN-SUFFIX,wxtz.houmags.com,AdBlock\n - DOMAIN-SUFFIX,wxwm1.ikuailian.com,AdBlock\n - DOMAIN-SUFFIX,wxwm2.ikuailian.com,AdBlock\n - DOMAIN-SUFFIX,wy.ce22d.cn,AdBlock\n - DOMAIN-SUFFIX,wyhzzy.com,AdBlock\n - DOMAIN-SUFFIX,wysa.2wxb5.cn,AdBlock\n - DOMAIN-SUFFIX,wyt.wwetjy.com,AdBlock\n - DOMAIN-SUFFIX,wyttech.cn,AdBlock\n - DOMAIN-SUFFIX,wzaigo.com,AdBlock\n - DOMAIN-SUFFIX,wzj.ywrjgzs.com,AdBlock\n - DOMAIN-SUFFIX,wzjijia.com,AdBlock\n - DOMAIN-SUFFIX,x.120ask.com,AdBlock\n - DOMAIN-SUFFIX,x.9dagui.com,AdBlock\n - DOMAIN-SUFFIX,x.bidswitch.net,AdBlock\n - DOMAIN-SUFFIX,x.bikaer.com,AdBlock\n - DOMAIN-SUFFIX,x.castanet.net,AdBlock\n - DOMAIN-SUFFIX,x.cnxad.com,AdBlock\n - DOMAIN-SUFFIX,x.eroticity.net,AdBlock\n - DOMAIN-SUFFIX,x.heyzap.com,AdBlock\n - DOMAIN-SUFFIX,x.infzm.com,AdBlock\n - DOMAIN-SUFFIX,x.ligatus.com,AdBlock\n - DOMAIN-SUFFIX,x.vamaker.com,AdBlock\n - DOMAIN-SUFFIX,x.vipergirls.to,AdBlock\n - DOMAIN-SUFFIX,x.zhuyuanp.top,AdBlock\n - DOMAIN-SUFFIX,x01.aidata.io,AdBlock\n - DOMAIN-SUFFIX,x1.go.sohu.com,AdBlock\n - DOMAIN-SUFFIX,x9377a.com,AdBlock\n - DOMAIN-SUFFIX,xa9t.com,AdBlock\n - DOMAIN-SUFFIX,xabaitai.com,AdBlock\n - DOMAIN-SUFFIX,xabmjr.com,AdBlock\n - DOMAIN-SUFFIX,xacqp.com,AdBlock\n - DOMAIN-SUFFIX,xau.sxmutan.com,AdBlock\n - DOMAIN-SUFFIX,xavingtsun.com,AdBlock\n - DOMAIN-SUFFIX,xbp.code.weddingeeos.com,AdBlock\n - DOMAIN-SUFFIX,xbtw.com,AdBlock\n - DOMAIN-SUFFIX,xbzzzx.com,AdBlock\n - DOMAIN-SUFFIX,xc.08an.com,AdBlock\n - DOMAIN-SUFFIX,xc.macd.cn,AdBlock\n - DOMAIN-SUFFIX,xc.mydrivers.com,AdBlock\n - DOMAIN-SUFFIX,xcclzs.com,AdBlock\n - DOMAIN-SUFFIX,xcdf.cn,AdBlock\n - DOMAIN-SUFFIX,xchgx.com,AdBlock\n - DOMAIN-SUFFIX,xcjy876.com,AdBlock\n - DOMAIN-SUFFIX,xco.qwxcs.com,AdBlock\n - DOMAIN-SUFFIX,xcy8.com,AdBlock\n - DOMAIN-SUFFIX,xcyjzs.net,AdBlock\n - DOMAIN-SUFFIX,xcyrc.com,AdBlock\n - DOMAIN-SUFFIX,xd.code.tanwanyx.com,AdBlock\n - DOMAIN-SUFFIX,xdadevelopers.browsi.mobi,AdBlock\n - DOMAIN-SUFFIX,xdbwc.com,AdBlock\n - DOMAIN-SUFFIX,xdcqcyp.com,AdBlock\n - DOMAIN-SUFFIX,xdcs-collector.ximalaya.com,AdBlock\n - DOMAIN-SUFFIX,xdyjt.com,AdBlock\n - DOMAIN-SUFFIX,xe2c.com,AdBlock\n - DOMAIN-SUFFIX,xf.yellowto.com,AdBlock\n - DOMAIN-SUFFIX,xfo.monesyy.com,AdBlock\n - DOMAIN-SUFFIX,xfywn.com,AdBlock\n - DOMAIN-SUFFIX,xgcsr.com,AdBlock\n - DOMAIN-SUFFIX,xgmc6lu8fs.me,AdBlock\n - DOMAIN-SUFFIX,xhbqczl.com,AdBlock\n - DOMAIN-SUFFIX,xhmrv.com,AdBlock\n - DOMAIN-SUFFIX,xhsxgmt.cn,AdBlock\n - DOMAIN-SUFFIX,xhsxgnt.cn,AdBlock\n - DOMAIN-SUFFIX,xhtd.99hg.wang,AdBlock\n - DOMAIN-SUFFIX,xhxnkyy.com,AdBlock\n - DOMAIN-SUFFIX,xhydrs.cn,AdBlock\n - DOMAIN-SUFFIX,xi.liuxiaoer.com,AdBlock\n - DOMAIN-SUFFIX,xia.huishenghuiying.com,AdBlock\n - DOMAIN-SUFFIX,xia.jihehuaban.com,AdBlock\n - DOMAIN-SUFFIX,xiacai.com,AdBlock\n - DOMAIN-SUFFIX,xiacaidd.com,AdBlock\n - DOMAIN-SUFFIX,xianliao.me,AdBlock\n - DOMAIN-SUFFIX,xiaobiaoucai.cn,AdBlock\n - DOMAIN-SUFFIX,xiaohei.com,AdBlock\n - DOMAIN-SUFFIX,xiaohuau.xyz,AdBlock\n - DOMAIN-SUFFIX,xiaohui2.cn,AdBlock\n - DOMAIN-SUFFIX,xiaomiir.yaokantv.com,AdBlock\n - DOMAIN-SUFFIX,XiaoQiang,AdBlock\n - DOMAIN-SUFFIX,xiaoshuo.kp53.cn,AdBlock\n - DOMAIN-SUFFIX,xiaoshuo.zhandao.net,AdBlock\n - DOMAIN-SUFFIX,xiaoyang.mobi,AdBlock\n - DOMAIN-SUFFIX,xiaoyuanzuqiu.cn,AdBlock\n - DOMAIN-SUFFIX,xiaoyutiao.com,AdBlock\n - DOMAIN-SUFFIX,xiaozhen.com,AdBlock\n - DOMAIN-SUFFIX,xiaozhishi852.com,AdBlock\n - DOMAIN-SUFFIX,xiaxuanfu.com,AdBlock\n - DOMAIN-SUFFIX,xiazai.cdren.com,AdBlock\n - DOMAIN-SUFFIX,xiazai.downok.com,AdBlock\n - DOMAIN-SUFFIX,xibao100.com,AdBlock\n - DOMAIN-SUFFIX,xibei70.com,AdBlock\n - DOMAIN-SUFFIX,xifatime.com,AdBlock\n - DOMAIN-SUFFIX,xihashuale.com,AdBlock\n - DOMAIN-SUFFIX,xihuashuale.com,AdBlock\n - DOMAIN-SUFFIX,xilele.com,AdBlock\n - DOMAIN-SUFFIX,xiliweisha.cn,AdBlock\n - DOMAIN-SUFFIX,xin.ygqczh.com,AdBlock\n - DOMAIN-SUFFIX,xinasiaj.com,AdBlock\n - DOMAIN-SUFFIX,xinghao89.com,AdBlock\n - DOMAIN-SUFFIX,xingjuhe.com,AdBlock\n - DOMAIN-SUFFIX,xiniuz.com,AdBlock\n - DOMAIN-SUFFIX,xinju.cc,AdBlock\n - DOMAIN-SUFFIX,xinray.com,AdBlock\n - DOMAIN-SUFFIX,xinsheng.net,AdBlock\n - DOMAIN-SUFFIX,xiongdong.com,AdBlock\n - DOMAIN-SUFFIX,xiuxiu.android.dl.meitu.com,AdBlock\n - DOMAIN-SUFFIX,xiuxiu.mobile.meitudata.com,AdBlock\n - DOMAIN-SUFFIX,xj40666.vip,AdBlock\n - DOMAIN-SUFFIX,xji.qwxcs.com,AdBlock\n - DOMAIN-SUFFIX,xjidian.com,AdBlock\n - DOMAIN-SUFFIX,xjq.jxmqkj.com,AdBlock\n - DOMAIN-SUFFIX,xk2012.com,AdBlock\n - DOMAIN-SUFFIX,xkwfao.com,AdBlock\n - DOMAIN-SUFFIX,xlmc.sandai.net,AdBlock\n - DOMAIN-SUFFIX,xls.go.sohu.com,AdBlock\n - DOMAIN-SUFFIX,xlwnx.com,AdBlock\n - DOMAIN-SUFFIX,xlylqx.com,AdBlock\n - DOMAIN-SUFFIX,xm9178.com,AdBlock\n - DOMAIN-SUFFIX,xmcmn.com,AdBlock\n - DOMAIN-SUFFIX,xmcxz.com,AdBlock\n - DOMAIN-SUFFIX,xmindchina.net,AdBlock\n - DOMAIN-SUFFIX,xmnmeu.cn,AdBlock\n - DOMAIN-SUFFIX,xmrts.com,AdBlock\n - DOMAIN-SUFFIX,xmshqh.com,AdBlock\n - DOMAIN-SUFFIX,xmsqz.com,AdBlock\n - DOMAIN-SUFFIX,xnjpg.com,AdBlock\n - DOMAIN-SUFFIX,xoredi.com,AdBlock\n - DOMAIN-SUFFIX,xp3366.com,AdBlock\n - DOMAIN-SUFFIX,xpcy.m.gxwztv.com,AdBlock\n - DOMAIN-SUFFIX,xpe.cxaerp.com,AdBlock\n - DOMAIN-SUFFIX,xpj1.net,AdBlock\n - DOMAIN-SUFFIX,xpj2.net,AdBlock\n - DOMAIN-SUFFIX,xpj3.net,AdBlock\n - DOMAIN-SUFFIX,xpj4.net,AdBlock\n - DOMAIN-SUFFIX,xpj8088.com,AdBlock\n - DOMAIN-SUFFIX,xpjkf888.com,AdBlock\n - DOMAIN-SUFFIX,xpjylc9977.com,AdBlock\n - DOMAIN-SUFFIX,xpqfc.com,AdBlock\n - DOMAIN-SUFFIX,xq12.com,AdBlock\n - DOMAIN-SUFFIX,xq199.com,AdBlock\n - DOMAIN-SUFFIX,xrain.net,AdBlock\n - DOMAIN-SUFFIX,xray.jebe.renren.com,AdBlock\n - DOMAIN-SUFFIX,xs.1drj.com,AdBlock\n - DOMAIN-SUFFIX,xs.he9630.com,AdBlock\n - DOMAIN-SUFFIX,xs.houyi.baofeng.net,AdBlock\n - DOMAIN-SUFFIX,xs.swagger1.com,AdBlock\n - DOMAIN-SUFFIX,xshellcn.com,AdBlock\n - DOMAIN-SUFFIX,xstar.cc,AdBlock\n - DOMAIN-SUFFIX,xszqapp.com,AdBlock\n - DOMAIN-SUFFIX,xtcdbb.cn,AdBlock\n - DOMAIN-SUFFIX,xtgreat.com,AdBlock\n - DOMAIN-SUFFIX,xtruh.uranus.sogou.com,AdBlock\n - DOMAIN-SUFFIX,xtwjx.cn,AdBlock\n - DOMAIN-SUFFIX,xtxa.net,AdBlock\n - DOMAIN-SUFFIX,xtzxmy.com,AdBlock\n - DOMAIN-SUFFIX,xuanmeiguoji.com,AdBlock\n - DOMAIN-SUFFIX,xue.zbyw.cn,AdBlock\n - DOMAIN-SUFFIX,xul478.com,AdBlock\n - DOMAIN-SUFFIX,xulizui6.com,AdBlock\n - DOMAIN-SUFFIX,xx.m.gxwztv.com,AdBlock\n - DOMAIN-SUFFIX,xxad.cc,AdBlock\n - DOMAIN-SUFFIX,xxeden.com,AdBlock\n - DOMAIN-SUFFIX,xxguan.cn,AdBlock\n - DOMAIN-SUFFIX,xxhrd.com,AdBlock\n - DOMAIN-SUFFIX,xxkhh.com,AdBlock\n - DOMAIN-SUFFIX,xxlargepop.com,AdBlock\n - DOMAIN-SUFFIX,xxp.gytygc.com,AdBlock\n - DOMAIN-SUFFIX,xxwkjl.com,AdBlock\n - DOMAIN-SUFFIX,xxxa.aikeapp.com,AdBlock\n - DOMAIN-SUFFIX,xxyzwtsylw.com,AdBlock\n - DOMAIN-SUFFIX,xy.com,AdBlock\n - DOMAIN-SUFFIX,xy.shijialianzuishuai.com,AdBlock\n - DOMAIN-SUFFIX,xycnz.com,AdBlock\n - DOMAIN-SUFFIX,xyd.sxmdxy.com,AdBlock\n - DOMAIN-SUFFIX,xyimg.net,AdBlock\n - DOMAIN-SUFFIX,xyly2016.com,AdBlock\n - DOMAIN-SUFFIX,xyqptm.com,AdBlock\n - DOMAIN-SUFFIX,xyqxr.com,AdBlock\n - DOMAIN-SUFFIX,xyrhd.com,AdBlock\n - DOMAIN-SUFFIX,xyrkl.com,AdBlock\n - DOMAIN-SUFFIX,xyssp.com,AdBlock\n - DOMAIN-SUFFIX,xytom.com,AdBlock\n - DOMAIN-SUFFIX,xyxy01.com,AdBlock\n - DOMAIN-SUFFIX,xyy.code.weddingeeos.com,AdBlock\n - DOMAIN-SUFFIX,xz.ercfh.com,AdBlock\n - DOMAIN-SUFFIX,xz-development.oss-cn-beijing.aliyuncs.com,AdBlock\n - DOMAIN-SUFFIX,xzq.greenxf.net,AdBlock\n - DOMAIN-SUFFIX,xztms.com,AdBlock\n - DOMAIN-SUFFIX,xzyituo.com,AdBlock\n - DOMAIN-SUFFIX,xzzyi.com,AdBlock\n - DOMAIN-SUFFIX,y.3957957.com,AdBlock\n - DOMAIN-SUFFIX,y.damifan.cn,AdBlock\n - DOMAIN-SUFFIX,y.gwylm.com,AdBlock\n - DOMAIN-SUFFIX,y.hk9600.com,AdBlock\n - DOMAIN-SUFFIX,y.hzht666.com,AdBlock\n - DOMAIN-SUFFIX,y.shuoshuocm.com,AdBlock\n - DOMAIN-SUFFIX,y.xinghao89.com,AdBlock\n - DOMAIN-SUFFIX,y.zxwdw.com,AdBlock\n - DOMAIN-SUFFIX,y0.cn,AdBlock\n - DOMAIN-SUFFIX,yadro.ru,AdBlock\n - DOMAIN-SUFFIX,yads.c.yimg.jp,AdBlock\n - DOMAIN-SUFFIX,yads.yahoo.co.jp,AdBlock\n - DOMAIN-SUFFIX,yageben.com,AdBlock\n - DOMAIN-SUFFIX,yam.adsbro.com,AdBlock\n - DOMAIN-SUFFIX,yandui.com,AdBlock\n - DOMAIN-SUFFIX,yangdasen.cn,AdBlock\n - DOMAIN-SUFFIX,yanglaopt.net,AdBlock\n - DOMAIN-SUFFIX,yao.zzsdjq.com,AdBlock\n - DOMAIN-SUFFIX,yaohq.com,AdBlock\n - DOMAIN-SUFFIX,yatemy.cn,AdBlock\n - DOMAIN-SUFFIX,yb.torchbrowser.com,AdBlock\n - DOMAIN-SUFFIX,ybtianxi.com,AdBlock\n - DOMAIN-SUFFIX,yccdn.com,AdBlock\n - DOMAIN-SUFFIX,ychml.com,AdBlock\n - DOMAIN-SUFFIX,ychun03.com,AdBlock\n - DOMAIN-SUFFIX,yd126.com,AdBlock\n - DOMAIN-SUFFIX,ydjs.zol.com.cn,AdBlock\n - DOMAIN-SUFFIX,ydlnt.com,AdBlock\n - DOMAIN-SUFFIX,ydpushserver.youdao.com,AdBlock\n - DOMAIN-SUFFIX,ydqzkj.com,AdBlock\n - DOMAIN-SUFFIX,yea.uploadimagex.com,AdBlock\n - DOMAIN-SUFFIX,yeabble.com,AdBlock\n - DOMAIN-SUFFIX,yeas.yahoo.co.jp,AdBlock\n - DOMAIN-SUFFIX,yee.js.cn,AdBlock\n - DOMAIN-SUFFIX,yellowto.com,AdBlock\n - DOMAIN-SUFFIX,yengo.com,AdBlock\n - DOMAIN-SUFFIX,yesbeby.whies.info,AdBlock\n - DOMAIN-SUFFIX,yess.imneinei.com,AdBlock\n - DOMAIN-SUFFIX,yezilm.com,AdBlock\n - DOMAIN-SUFFIX,yf898.com,AdBlock\n - DOMAIN-SUFFIX,yfcode.m.gxwztv.com,AdBlock\n - DOMAIN-SUFFIX,yfxpcode.m.gxwztv.com,AdBlock\n - DOMAIN-SUFFIX,yfycy.com,AdBlock\n - DOMAIN-SUFFIX,yhtcd.com,AdBlock\n - DOMAIN-SUFFIX,yhzm.cc,AdBlock\n - DOMAIN-SUFFIX,yicha.cn,AdBlock\n - DOMAIN-SUFFIX,yidulive.net,AdBlock\n - DOMAIN-SUFFIX,yieldmanager.com,AdBlock\n - DOMAIN-SUFFIX,yigao.com,AdBlock\n - DOMAIN-SUFFIX,yigyx.com,AdBlock\n - DOMAIN-SUFFIX,yihuifu.cn,AdBlock\n - DOMAIN-SUFFIX,yiiwoo.com,AdBlock\n - DOMAIN-SUFFIX,yijia2009.com,AdBlock\n - DOMAIN-SUFFIX,yijifen.com,AdBlock\n - DOMAIN-SUFFIX,yiluup.com,AdBlock\n - DOMAIN-SUFFIX,yin1.zgpingshu.com,AdBlock\n - DOMAIN-SUFFIX,yingxiao.baidu.com,AdBlock\n - DOMAIN-SUFFIX,yinhaijuan.com,AdBlock\n - DOMAIN-SUFFIX,yinmong.com,AdBlock\n - DOMAIN-SUFFIX,yinooo.com,AdBlock\n - DOMAIN-SUFFIX,yinyuehu.cn,AdBlock\n - DOMAIN-SUFFIX,yiqifa.com,AdBlock\n - DOMAIN-SUFFIX,yiranxian.cn,AdBlock\n - DOMAIN-SUFFIX,yitaopt.com,AdBlock\n - DOMAIN-SUFFIX,yiwk.com,AdBlock\n - DOMAIN-SUFFIX,yiwuds.com,AdBlock\n - DOMAIN-SUFFIX,yixui.com,AdBlock\n - DOMAIN-SUFFIX,yizhenya.com,AdBlock\n - DOMAIN-SUFFIX,yjqiqi.com,AdBlock\n - DOMAIN-SUFFIX,yk0712.com,AdBlock\n - DOMAIN-SUFFIX,ykbei.com,AdBlock\n - DOMAIN-SUFFIX,ykjmy.com,AdBlock\n - DOMAIN-SUFFIX,yktj.yzz.cn,AdBlock\n - DOMAIN-SUFFIX,ykxwn.com,AdBlock\n - DOMAIN-SUFFIX,yl850555.com,AdBlock\n - DOMAIN-SUFFIX,ylads.yaolan.com,AdBlock\n - DOMAIN-SUFFIX,ylog.hiido.com,AdBlock\n - DOMAIN-SUFFIX,ylunion.com,AdBlock\n - DOMAIN-SUFFIX,ylwy168.com,AdBlock\n - DOMAIN-SUFFIX,ymapp.com,AdBlock\n - DOMAIN-SUFFIX,ymcdn.cn,AdBlock\n - DOMAIN-SUFFIX,ymcqb.com,AdBlock\n - DOMAIN-SUFFIX,ymrzr.com,AdBlock\n - DOMAIN-SUFFIX,yn.001fzc.com,AdBlock\n - DOMAIN-SUFFIX,ynbojie.com,AdBlock\n - DOMAIN-SUFFIX,yndianju.com,AdBlock\n - DOMAIN-SUFFIX,ynmbz.com,AdBlock\n - DOMAIN-SUFFIX,yongkang6.com,AdBlock\n - DOMAIN-SUFFIX,yongv.com,AdBlock\n - DOMAIN-SUFFIX,yoo.yiiyoo.net,AdBlock\n - DOMAIN-SUFFIX,yooli.com,AdBlock\n - DOMAIN-SUFFIX,you1ad.com,AdBlock\n - DOMAIN-SUFFIX,youfumei.com,AdBlock\n - DOMAIN-SUFFIX,youjia2016.com,AdBlock\n - DOMAIN-SUFFIX,youka.la,AdBlock\n - DOMAIN-SUFFIX,youle.tom.com,AdBlock\n - DOMAIN-SUFFIX,youle55.com,AdBlock\n - DOMAIN-SUFFIX,youmi.net,AdBlock\n - DOMAIN-SUFFIX,youmsm.com,AdBlock\n - DOMAIN-SUFFIX,yousee.com,AdBlock\n - DOMAIN-SUFFIX,youxi.kugou.com,AdBlock\n - DOMAIN-SUFFIX,youxiaoad.com,AdBlock\n - DOMAIN-SUFFIX,youxicool.net,AdBlock\n - DOMAIN-SUFFIX,youzehui.com,AdBlock\n - DOMAIN-SUFFIX,yoyi.com.cn,AdBlock\n - DOMAIN-SUFFIX,yoyi.tv,AdBlock\n - DOMAIN-SUFFIX,ypmeiwen.com,AdBlock\n - DOMAIN-SUFFIX,ypmob.com,AdBlock\n - DOMAIN-SUFFIX,yqjxzw.com,AdBlock\n - DOMAIN-SUFFIX,yqw88.com,AdBlock\n - DOMAIN-SUFFIX,yrt7dgkf.exashare.com,AdBlock\n - DOMAIN-SUFFIX,yrxmr.com,AdBlock\n - DOMAIN-SUFFIX,ysej.code.weddingeeos.com,AdBlock\n - DOMAIN-SUFFIX,ysjwj.com,AdBlock\n - DOMAIN-SUFFIX,ysm.hauchi.com.tw,AdBlock\n - DOMAIN-SUFFIX,ysm.yahoo.com,AdBlock\n - DOMAIN-SUFFIX,yt-adp.nosdn.127.net,AdBlock\n - DOMAIN-SUFFIX,ytapi1.nagezan.net,AdBlock\n - DOMAIN-SUFFIX,ytdksb.com,AdBlock\n - DOMAIN-SUFFIX,ytguowang.com,AdBlock\n - DOMAIN-SUFFIX,ytmx.2r3485.cn,AdBlock\n - DOMAIN-SUFFIX,yts.ytsyyey.com,AdBlock\n - DOMAIN-SUFFIX,ytsyyey.com,AdBlock\n - DOMAIN-SUFFIX,yuanchengxiezuo.com,AdBlock\n - DOMAIN-SUFFIX,yuanming.net,AdBlock\n - DOMAIN-SUFFIX,yueyelive.com,AdBlock\n - DOMAIN-SUFFIX,yug8.com,AdBlock\n - DOMAIN-SUFFIX,yukhj.com,AdBlock\n - DOMAIN-SUFFIX,yule8.net,AdBlock\n - DOMAIN-SUFFIX,yulzs.com,AdBlock\n - DOMAIN-SUFFIX,yumcs.xiaohuau.xyz,AdBlock\n - DOMAIN-SUFFIX,yun.lvehaisen.com,AdBlock\n - DOMAIN-SUFFIX,yun.rili.cn,AdBlock\n - DOMAIN-SUFFIX,yun.sifuhe.cn,AdBlock\n - DOMAIN-SUFFIX,yun.tuia.cn,AdBlock\n - DOMAIN-SUFFIX,yun.tuisnake.com,AdBlock\n - DOMAIN-SUFFIX,yun.yuyiya.com,AdBlock\n - DOMAIN-SUFFIX,yun1.yahoo001.com,AdBlock\n - DOMAIN-SUFFIX,yunanfuwuqi.com,AdBlock\n - DOMAIN-SUFFIX,yunbofangbt.com,AdBlock\n - DOMAIN-SUFFIX,yundingjiayuan.com,AdBlock\n - DOMAIN-SUFFIX,yunjiasu.com,AdBlock\n - DOMAIN-SUFFIX,yunshipei.com,AdBlock\n - DOMAIN-SUFFIX,yunxuu.com,AdBlock\n - DOMAIN-SUFFIX,yuyue008.cn,AdBlock\n - DOMAIN-SUFFIX,ywjxsp168.cn,AdBlock\n - DOMAIN-SUFFIX,yx.lenovomm.com,AdBlock\n - DOMAIN-SUFFIX,yxhxs.com,AdBlock\n - DOMAIN-SUFFIX,yxjad.com,AdBlock\n - DOMAIN-SUFFIX,yxs.tymsyx.com,AdBlock\n - DOMAIN-SUFFIX,yxszy.com,AdBlock\n - DOMAIN-SUFFIX,yxxwyz.com,AdBlock\n - DOMAIN-SUFFIX,yy58ju.com,AdBlock\n - DOMAIN-SUFFIX,yyb.pc6.com,AdBlock\n - DOMAIN-SUFFIX,yyffeicd.m.qxs.la,AdBlock\n - DOMAIN-SUFFIX,yyjxgm.net,AdBlock\n - DOMAIN-SUFFIX,yyp17.com,AdBlock\n - DOMAIN-SUFFIX,yyt.irs01.com,AdBlock\n - DOMAIN-SUFFIX,yzaosite.com,AdBlock\n - DOMAIN-SUFFIX,yzh.jyjhkz.com,AdBlock\n - DOMAIN-SUFFIX,yzh360.com,AdBlock\n - DOMAIN-SUFFIX,yzygo.com,AdBlock\n - DOMAIN-SUFFIX,yzytb.com,AdBlock\n - DOMAIN-SUFFIX,z.clickvip.shop,AdBlock\n - DOMAIN-SUFFIX,z.moatads.com,AdBlock\n - DOMAIN-SUFFIX,z.nowscore.com,AdBlock\n - DOMAIN-SUFFIX,z.sora.yoyi.com.cn,AdBlock\n - DOMAIN-SUFFIX,z1.zedo.com,AdBlock\n - DOMAIN-SUFFIX,z1hihu.xmcimg.com,AdBlock\n - DOMAIN-SUFFIX,z2.lnymd.com,AdBlock\n - DOMAIN-SUFFIX,zads.care2.com,AdBlock\n - DOMAIN-SUFFIX,zae.gzzena.com,AdBlock\n - DOMAIN-SUFFIX,zamar.cn,AdBlock\n - DOMAIN-SUFFIX,zampdsp.com,AdBlock\n - DOMAIN-SUFFIX,zantainet.com,AdBlock\n - DOMAIN-SUFFIX,zapads.zapak.com,AdBlock\n - DOMAIN-SUFFIX,zb.nxing.cn,AdBlock\n - DOMAIN-SUFFIX,zbrushcn.com,AdBlock\n - DOMAIN-SUFFIX,zbz.m.qxs.la,AdBlock\n - DOMAIN-SUFFIX,zcdsp.com,AdBlock\n - DOMAIN-SUFFIX,zcrtd.com,AdBlock\n - DOMAIN-SUFFIX,zdjby.cn,AdBlock\n - DOMAIN-SUFFIX,zdw.w8.com.cn,AdBlock\n - DOMAIN-SUFFIX,ze5.com,AdBlock\n - DOMAIN-SUFFIX,zedo.com,AdBlock\n - DOMAIN-SUFFIX,zeus.qj.net,AdBlock\n - DOMAIN-SUFFIX,zgc66.com,AdBlock\n - DOMAIN-SUFFIX,zgdfz6h7po.me,AdBlock\n - DOMAIN-SUFFIX,zgfszs.com,AdBlock\n - DOMAIN-SUFFIX,zgjkv.com,AdBlock\n - DOMAIN-SUFFIX,zgksb.com,AdBlock\n - DOMAIN-SUFFIX,zgty365.com,AdBlock\n - DOMAIN-SUFFIX,zgunion.cn,AdBlock\n - DOMAIN-SUFFIX,zgyemy.com,AdBlock\n - DOMAIN-SUFFIX,zhanzhang.net,AdBlock\n - DOMAIN-SUFFIX,zhao258.com,AdBlock\n - DOMAIN-SUFFIX,zhaoshang8.com,AdBlock\n - DOMAIN-SUFFIX,zhaozecheng.cn,AdBlock\n - DOMAIN-SUFFIX,zh-cn.shenyun.com,AdBlock\n - DOMAIN-SUFFIX,zh-cn.shenyun.org,AdBlock\n - DOMAIN-SUFFIX,zheng.cs12d.com,AdBlock\n - DOMAIN-SUFFIX,zhengjian.org,AdBlock\n - DOMAIN-SUFFIX,zhenxinet.com,AdBlock\n - DOMAIN-SUFFIX,zhichi08.com,AdBlock\n - DOMAIN-SUFFIX,zhidian3g.cn,AdBlock\n - DOMAIN-SUFFIX,zhifenjie.com,AdBlock\n - DOMAIN-SUFFIX,zhihei.com,AdBlock\n - DOMAIN-SUFFIX,zhiong.net,AdBlock\n - DOMAIN-SUFFIX,zhiyuanteam.com,AdBlock\n - DOMAIN-SUFFIX,zhiziyun.com,AdBlock\n - DOMAIN-SUFFIX,zhongchouyan.com,AdBlock\n - DOMAIN-SUFFIX,zhongzicili.cc,AdBlock\n - DOMAIN-SUFFIX,zhtjdl.com,AdBlock\n - DOMAIN-SUFFIX,zhuanfakong.com,AdBlock\n - DOMAIN-SUFFIX,zhuba8.com,AdBlock\n - DOMAIN-SUFFIX,zhudiaosz.com,AdBlock\n - DOMAIN-SUFFIX,zhuichaguoji.org,AdBlock\n - DOMAIN-SUFFIX,zhushou.2345.com,AdBlock\n - DOMAIN-SUFFIX,zhuuv.maoyumao.net,AdBlock\n - DOMAIN-SUFFIX,zhwnlapi.etouch.cn,AdBlock\n - DOMAIN-SUFFIX,zhybzp.cn,AdBlock\n - DOMAIN-SUFFIX,zhzzx.com,AdBlock\n - DOMAIN-SUFFIX,zisunion.com,AdBlock\n - DOMAIN-SUFFIX,zizcy.com,AdBlock\n - DOMAIN-SUFFIX,zjbdt.com,AdBlock\n - DOMAIN-SUFFIX,zjhim.com,AdBlock\n - DOMAIN-SUFFIX,zjjgtz.com,AdBlock\n - DOMAIN-SUFFIX,zjm.zzmmkj.com,AdBlock\n - DOMAIN-SUFFIX,zkrdy.com,AdBlock\n - DOMAIN-SUFFIX,zlongad.com,AdBlock\n - DOMAIN-SUFFIX,zlsw.nnjxqd.com,AdBlock\n - DOMAIN-SUFFIX,zmj.guanqinjie.cn,AdBlock\n - DOMAIN-SUFFIX,znsv.baidu.com,AdBlock\n - DOMAIN-SUFFIX,zo66.com,AdBlock\n - DOMAIN-SUFFIX,zp22938576.com,AdBlock\n - DOMAIN-SUFFIX,zpe.klre.18183.com,AdBlock\n - DOMAIN-SUFFIX,zq84.com,AdBlock\n - DOMAIN-SUFFIX,zqworks.com,AdBlock\n - DOMAIN-SUFFIX,zqzxz.com,AdBlock\n - DOMAIN-SUFFIX,zreder.com,AdBlock\n - DOMAIN-SUFFIX,zrpfk.com,AdBlock\n - DOMAIN-SUFFIX,zs0613.mengchengbao.com,AdBlock\n - DOMAIN-SUFFIX,zs1111.youzue.com,AdBlock\n - DOMAIN-SUFFIX,zsdexun.com.cn,AdBlock\n - DOMAIN-SUFFIX,zshacker.com,AdBlock\n - DOMAIN-SUFFIX,zst.jzntxs.com,AdBlock\n - DOMAIN-SUFFIX,zsxpx.com,AdBlock\n - DOMAIN-SUFFIX,zszwcp.cn,AdBlock\n - DOMAIN-SUFFIX,zt2088.com,AdBlock\n - DOMAIN-SUFFIX,ztidu.com,AdBlock\n - DOMAIN-SUFFIX,ztxbd.com,AdBlock\n - DOMAIN-SUFFIX,zuche321.com,AdBlock\n - DOMAIN-SUFFIX,zuiceshi.net,AdBlock\n - DOMAIN-SUFFIX,zuimeitianqi.inveno.com,AdBlock\n - DOMAIN-SUFFIX,zunmi.cn,AdBlock\n - DOMAIN-SUFFIX,zws.avvo.com,AdBlock\n - DOMAIN-SUFFIX,zx.baosmx.com,AdBlock\n - DOMAIN-SUFFIX,zxcs.ggwan.com,AdBlock\n - DOMAIN-SUFFIX,zxcs.linghit.com,AdBlock\n - DOMAIN-SUFFIX,zxh.bzshzx.com,AdBlock\n - DOMAIN-SUFFIX,zxjjzx.com,AdBlock\n - DOMAIN-SUFFIX,zxr.fzxrjx.com,AdBlock\n - DOMAIN-SUFFIX,zxziyuan.com,AdBlock\n - DOMAIN-SUFFIX,zybpj.com,AdBlock\n - DOMAIN-SUFFIX,zyf.fzdfwy.com,AdBlock\n - DOMAIN-SUFFIX,zymo.mps.weibo.com,AdBlock\n - DOMAIN-SUFFIX,zymro.com,AdBlock\n - DOMAIN-SUFFIX,zytwq.net,AdBlock\n - DOMAIN-SUFFIX,zyz.91friend.com,AdBlock\n - DOMAIN-SUFFIX,zyz1.91friend.com,AdBlock\n - DOMAIN-SUFFIX,zz.bdstatic.com,AdBlock\n - DOMAIN-SUFFIX,zz123.com,AdBlock\n - DOMAIN-SUFFIX,zzbaowen.com,AdBlock\n - DOMAIN-SUFFIX,zzcw.office-mall.net,AdBlock\n - DOMAIN-SUFFIX,zzd6.com,AdBlock\n - DOMAIN-SUFFIX,zzjs2.firefang.cn,AdBlock\n - DOMAIN-SUFFIX,zzpush.58.com,AdBlock\n - DOMAIN-SUFFIX,zzrcz.com,AdBlock\n - DOMAIN-SUFFIX,zzsx8.com,AdBlock\n - DOMAIN-SUFFIX,zzy.mipujia.com,AdBlock\n - DOMAIN-SUFFIX,zzy1.mipujia.com,AdBlock\n - DOMAIN-SUFFIX,zzy1.quyaoya.com,AdBlock\n - DOMAIN-SUFFIX,zzz7.52896368.com,AdBlock\n - DOMAIN-SUFFIX,zzzzz4.52896368.com,AdBlock\n - DOMAIN-SUFFIX,5534edee5a.com,AdBlock\n - DOMAIN-SUFFIX,ea778a21c7.com,AdBlock\n - DOMAIN-SUFFIX,baidustatic.com,AdBlock\n - DOMAIN,duclick.baidu.com,AdBlock\n - DOMAIN,hm.baidu.com,AdBlock\n - DOMAIN,hmma.baidu.com,AdBlock\n - DOMAIN,mobads.baidu.com,AdBlock\n - DOMAIN,mobads-logs.baidu.com,AdBlock\n - DOMAIN,nsclick.baidu.com,AdBlock\n - DOMAIN,wn.pos.baidu.com,AdBlock\n - DOMAIN,ps.map.baidu.com,AdBlock\n - DOMAIN,offnavi.map.baidu.com,AdBlock\n - DOMAIN,newvector.map.baidu.com,AdBlock\n - DOMAIN,ulog.imap.baidu.com,AdBlock\n - DOMAIN,newloc.map.n.shifen.com,AdBlock\n - DOMAIN,miniapp.bilibili.com,AdBlock\n - DOMAIN,thirdparty.biliapi.com,AdBlock\n - DOMAIN,log.star.ele.me,AdBlock\n - DOMAIN,ad.bn.netease.com,AdBlock\n - DOMAIN,ad.yixin.im,AdBlock\n - DOMAIN,iadmat.nosdn.127.net,AdBlock\n - DOMAIN,iadmusicmat.music.126.net,AdBlock\n - DOMAIN,iadmusicmatvideo.music.126.net,AdBlock\n - DOMAIN,impservice.dictapp.youdao.com,AdBlock\n - DOMAIN,impservice.youdao.com,AdBlock\n - DOMAIN,log.yex.youdao.com,AdBlock\n - DOMAIN,log-yex.youdao.com,AdBlock\n - DOMAIN,mr.da.netease.com,AdBlock\n - DOMAIN,n.3g.163.com,AdBlock\n - DOMAIN,nex.163.com,AdBlock\n - DOMAIN,pr.da.netease.com,AdBlock\n - DOMAIN,rd.da.netease.com,AdBlock\n - DOMAIN,wr.da.netease.com,AdBlock\n - DOMAIN,yt-adp.nosdn.127.net,AdBlock\n - DOMAIN,appcloud2.in.zhihu.com,AdBlock\n - DOMAIN,mqtt.zhihu.com,AdBlock\n - DOMAIN,sugar.zhihu.com,AdBlock\n - DOMAIN,zhihu-analytics.zhihu.com,AdBlock\n - DOMAIN,zhihu-web-analytics.zhihu.com,AdBlock\n - DOMAIN,118.89.204.198,AdBlock\n - DOMAIN-SUFFIX,xdrig.com,AdBlock\n - DOMAIN-SUFFIX,zhihu.xmcimg.com,AdBlock\n - IP-CIDR,39.107.15.115/32,AdBlock,no-resolve\n - IP-CIDR,47.89.59.182/32,AdBlock,no-resolve\n - IP-CIDR,103.49.209.27/32,AdBlock,no-resolve\n - IP-CIDR,118.89.204.198/32,AdBlock,no-resolve\n - IP-CIDR,123.56.152.96/32,AdBlock,no-resolve\n - IP-CIDR6,2402:4e00:1200:ed00:0:9089:6dac:96b6/128,AdBlock,no-resolve\n - IP-CIDR,61.160.200.223/32,AdBlock,no-resolve\n - IP-CIDR,61.160.200.242/32,AdBlock,no-resolve\n - IP-CIDR,61.160.200.252/32,AdBlock,no-resolve\n - IP-CIDR,61.174.50.214/32,AdBlock,no-resolve\n - IP-CIDR,111.175.220.163/32,AdBlock,no-resolve\n - IP-CIDR,111.175.220.164/32,AdBlock,no-resolve\n - IP-CIDR,124.232.160.178/32,AdBlock,no-resolve\n - IP-CIDR,175.6.223.15/32,AdBlock,no-resolve\n - IP-CIDR,183.59.53.237/32,AdBlock,no-resolve\n - IP-CIDR,218.93.127.37/32,AdBlock,no-resolve\n - IP-CIDR,221.228.17.152/32,AdBlock,no-resolve\n - IP-CIDR,221.231.6.79/32,AdBlock,no-resolve\n - IP-CIDR,222.186.61.91/32,AdBlock,no-resolve\n - IP-CIDR,222.186.61.95/32,AdBlock,no-resolve\n - IP-CIDR,222.186.61.96/32,AdBlock,no-resolve\n - IP-CIDR,222.186.61.97/32,AdBlock,no-resolve\n - IP-CIDR,106.75.231.48/32,AdBlock,no-resolve\n - IP-CIDR,119.4.249.166/32,AdBlock,no-resolve\n - IP-CIDR,220.196.52.141/32,AdBlock,no-resolve\n - IP-CIDR,221.6.4.148/32,AdBlock,no-resolve\n - IP-CIDR,114.247.28.96/32,AdBlock,no-resolve\n - IP-CIDR,221.179.131.72/32,AdBlock,no-resolve\n - IP-CIDR,221.179.140.145/32,AdBlock,no-resolve\n - IP-CIDR,10.72.25.0/24,AdBlock,no-resolve\n - IP-CIDR,115.182.16.79/32,AdBlock,no-resolve\n - IP-CIDR,118.144.88.126/32,AdBlock,no-resolve\n - IP-CIDR,118.144.88.215/32,AdBlock,no-resolve\n - IP-CIDR,120.76.189.132/32,AdBlock,no-resolve\n - IP-CIDR,124.14.21.147/32,AdBlock,no-resolve\n - IP-CIDR,124.14.21.151/32,AdBlock,no-resolve\n - IP-CIDR,180.166.52.24/32,AdBlock,no-resolve\n - IP-CIDR,220.115.251.25/32,AdBlock,no-resolve\n - IP-CIDR,222.73.156.235/32,AdBlock,no-resolve\n - DOMAIN-SUFFIX,fast.com,Netflix\n - DOMAIN-SUFFIX,netflix.ca,Netflix\n - DOMAIN-SUFFIX,netflix.com,Netflix\n - DOMAIN-SUFFIX,netflix.net,Netflix\n - DOMAIN-SUFFIX,netflixinvestor.com,Netflix\n - DOMAIN-SUFFIX,netflixtechblog.com,Netflix\n - DOMAIN-SUFFIX,nflxext.com,Netflix\n - DOMAIN-SUFFIX,nflximg.com,Netflix\n - DOMAIN-SUFFIX,nflximg.net,Netflix\n - DOMAIN-SUFFIX,nflxsearch.net,Netflix\n - DOMAIN-SUFFIX,nflxso.net,Netflix\n - DOMAIN-SUFFIX,nflxvideo.net,Netflix\n - DOMAIN-SUFFIX,netflix.com.edgesuite.net,Netflix\n - DOMAIN-KEYWORD,spotify,Spotify\n - DOMAIN-SUFFIX,pscdn.co,Spotify\n - DOMAIN-SUFFIX,scdn.co,Spotify\n - DOMAIN-SUFFIX,spoti.fi,Spotify\n - DOMAIN-SUFFIX,spotilocal.com,Spotify\n - DOMAIN-SUFFIX,bamgrid.com,Disney\n - DOMAIN-SUFFIX,cdn.registerdisney.go.com,Disney\n - DOMAIN-SUFFIX,disney-plus.net,Disney\n - DOMAIN-SUFFIX,disneyplus.com,Disney\n - DOMAIN-SUFFIX,disneynow.com,Disney\n - DOMAIN-SUFFIX,disneystreaming.com,Disney\n - DOMAIN-SUFFIX,dssott.com,Disney\n - DOMAIN-SUFFIX,googlevideo.com,YouTube\n - DOMAIN-SUFFIX,gvt1.com,YouTube\n - DOMAIN-SUFFIX,video.google.com,YouTube\n - DOMAIN-SUFFIX,youtu.be,YouTube\n - DOMAIN-SUFFIX,youtube.ae,YouTube\n - DOMAIN-SUFFIX,youtube.al,YouTube\n - DOMAIN-SUFFIX,youtube.am,YouTube\n - DOMAIN-SUFFIX,youtube.at,YouTube\n - DOMAIN-SUFFIX,youtube.az,YouTube\n - DOMAIN-SUFFIX,youtube.ba,YouTube\n - DOMAIN-SUFFIX,youtube.be,YouTube\n - DOMAIN-SUFFIX,youtube.bg,YouTube\n - DOMAIN-SUFFIX,youtube.bh,YouTube\n - DOMAIN-SUFFIX,youtube.bo,YouTube\n - DOMAIN-SUFFIX,youtube.by,YouTube\n - DOMAIN-SUFFIX,youtube.ca,YouTube\n - DOMAIN-SUFFIX,youtube.cat,YouTube\n - DOMAIN-SUFFIX,youtube.ch,YouTube\n - DOMAIN-SUFFIX,youtube.cl,YouTube\n - DOMAIN-SUFFIX,youtube.co,YouTube\n - DOMAIN-SUFFIX,youtube.co.ae,YouTube\n - DOMAIN-SUFFIX,youtube.co.at,YouTube\n - DOMAIN-SUFFIX,youtube.co.cr,YouTube\n - DOMAIN-SUFFIX,youtube.co.hu,YouTube\n - DOMAIN-SUFFIX,youtube.co.id,YouTube\n - DOMAIN-SUFFIX,youtube.co.il,YouTube\n - DOMAIN-SUFFIX,youtube.co.in,YouTube\n - DOMAIN-SUFFIX,youtube.co.jp,YouTube\n - DOMAIN-SUFFIX,youtube.co.ke,YouTube\n - DOMAIN-SUFFIX,youtube.co.kr,YouTube\n - DOMAIN-SUFFIX,youtube.co.ma,YouTube\n - DOMAIN-SUFFIX,youtube.co.nz,YouTube\n - DOMAIN-SUFFIX,youtube.co.th,YouTube\n - DOMAIN-SUFFIX,youtube.co.tz,YouTube\n - DOMAIN-SUFFIX,youtube.co.ug,YouTube\n - DOMAIN-SUFFIX,youtube.co.uk,YouTube\n - DOMAIN-SUFFIX,youtube.co.ve,YouTube\n - DOMAIN-SUFFIX,youtube.co.za,YouTube\n - DOMAIN-SUFFIX,youtube.co.zw,YouTube\n - DOMAIN-SUFFIX,youtube.com,YouTube\n - DOMAIN-SUFFIX,youtube.com.ar,YouTube\n - DOMAIN-SUFFIX,youtube.com.au,YouTube\n - DOMAIN-SUFFIX,youtube.com.az,YouTube\n - DOMAIN-SUFFIX,youtube.com.bd,YouTube\n - DOMAIN-SUFFIX,youtube.com.bh,YouTube\n - DOMAIN-SUFFIX,youtube.com.bo,YouTube\n - DOMAIN-SUFFIX,youtube.com.br,YouTube\n - DOMAIN-SUFFIX,youtube.com.by,YouTube\n - DOMAIN-SUFFIX,youtube.com.co,YouTube\n - DOMAIN-SUFFIX,youtube.com.do,YouTube\n - DOMAIN-SUFFIX,youtube.com.ec,YouTube\n - DOMAIN-SUFFIX,youtube.com.ee,YouTube\n - DOMAIN-SUFFIX,youtube.com.eg,YouTube\n - DOMAIN-SUFFIX,youtube.com.es,YouTube\n - DOMAIN-SUFFIX,youtube.com.gh,YouTube\n - DOMAIN-SUFFIX,youtube.com.gr,YouTube\n - DOMAIN-SUFFIX,youtube.com.gt,YouTube\n - DOMAIN-SUFFIX,youtube.com.hk,YouTube\n - DOMAIN-SUFFIX,youtube.com.hn,YouTube\n - DOMAIN-SUFFIX,youtube.com.hr,YouTube\n - DOMAIN-SUFFIX,youtube.com.jm,YouTube\n - DOMAIN-SUFFIX,youtube.com.jo,YouTube\n - DOMAIN-SUFFIX,youtube.com.kw,YouTube\n - DOMAIN-SUFFIX,youtube.com.lb,YouTube\n - DOMAIN-SUFFIX,youtube.com.lv,YouTube\n - DOMAIN-SUFFIX,youtube.com.ly,YouTube\n - DOMAIN-SUFFIX,youtube.com.mk,YouTube\n - DOMAIN-SUFFIX,youtube.com.mt,YouTube\n - DOMAIN-SUFFIX,youtube.com.mx,YouTube\n - DOMAIN-SUFFIX,youtube.com.my,YouTube\n - DOMAIN-SUFFIX,youtube.com.ng,YouTube\n - DOMAIN-SUFFIX,youtube.com.ni,YouTube\n - DOMAIN-SUFFIX,youtube.com.om,YouTube\n - DOMAIN-SUFFIX,youtube.com.pa,YouTube\n - DOMAIN-SUFFIX,youtube.com.pe,YouTube\n - DOMAIN-SUFFIX,youtube.com.ph,YouTube\n - DOMAIN-SUFFIX,youtube.com.pk,YouTube\n - DOMAIN-SUFFIX,youtube.com.pt,YouTube\n - DOMAIN-SUFFIX,youtube.com.py,YouTube\n - DOMAIN-SUFFIX,youtube.com.qa,YouTube\n - DOMAIN-SUFFIX,youtube.com.ro,YouTube\n - DOMAIN-SUFFIX,youtube.com.sa,YouTube\n - DOMAIN-SUFFIX,youtube.com.sg,YouTube\n - DOMAIN-SUFFIX,youtube.com.sv,YouTube\n - DOMAIN-SUFFIX,youtube.com.tn,YouTube\n - DOMAIN-SUFFIX,youtube.com.tr,YouTube\n - DOMAIN-SUFFIX,youtube.com.tw,YouTube\n - DOMAIN-SUFFIX,youtube.com.ua,YouTube\n - DOMAIN-SUFFIX,youtube.com.uy,YouTube\n - DOMAIN-SUFFIX,youtube.com.ve,YouTube\n - DOMAIN-SUFFIX,youtube.cr,YouTube\n - DOMAIN-SUFFIX,youtube.cz,YouTube\n - DOMAIN-SUFFIX,youtube.de,YouTube\n - DOMAIN-SUFFIX,youtube.dk,YouTube\n - DOMAIN-SUFFIX,youtube.ee,YouTube\n - DOMAIN-SUFFIX,youtube.es,YouTube\n - DOMAIN-SUFFIX,youtube.fi,YouTube\n - DOMAIN-SUFFIX,youtube.fr,YouTube\n - DOMAIN-SUFFIX,youtube.ge,YouTube\n - DOMAIN-SUFFIX,youtube.googleapis.com,YouTube\n - DOMAIN-SUFFIX,youtube.gr,YouTube\n - DOMAIN-SUFFIX,youtube.gt,YouTube\n - DOMAIN-SUFFIX,youtube.hk,YouTube\n - DOMAIN-SUFFIX,youtube.hr,YouTube\n - DOMAIN-SUFFIX,youtube.hu,YouTube\n - DOMAIN-SUFFIX,youtube.ie,YouTube\n - DOMAIN-SUFFIX,youtube.in,YouTube\n - DOMAIN-SUFFIX,youtube.iq,YouTube\n - DOMAIN-SUFFIX,youtube.is,YouTube\n - DOMAIN-SUFFIX,youtube.it,YouTube\n - DOMAIN-SUFFIX,youtube.jo,YouTube\n - DOMAIN-SUFFIX,youtube.jp,YouTube\n - DOMAIN-SUFFIX,youtube.kr,YouTube\n - DOMAIN-SUFFIX,youtube.kz,YouTube\n - DOMAIN-SUFFIX,youtube.la,YouTube\n - DOMAIN-SUFFIX,youtube.lk,YouTube\n - DOMAIN-SUFFIX,youtube.lt,YouTube\n - DOMAIN-SUFFIX,youtube.lu,YouTube\n - DOMAIN-SUFFIX,youtube.lv,YouTube\n - DOMAIN-SUFFIX,youtube.ly,YouTube\n - DOMAIN-SUFFIX,youtube.ma,YouTube\n - DOMAIN-SUFFIX,youtube.md,YouTube\n - DOMAIN-SUFFIX,youtube.me,YouTube\n - DOMAIN-SUFFIX,youtube.mk,YouTube\n - DOMAIN-SUFFIX,youtube.mn,YouTube\n - DOMAIN-SUFFIX,youtube.mx,YouTube\n - DOMAIN-SUFFIX,youtube.my,YouTube\n - DOMAIN-SUFFIX,youtube.ng,YouTube\n - DOMAIN-SUFFIX,youtube.ni,YouTube\n - DOMAIN-SUFFIX,youtube.nl,YouTube\n - DOMAIN-SUFFIX,youtube.no,YouTube\n - DOMAIN-SUFFIX,youtube.pa,YouTube\n - DOMAIN-SUFFIX,youtube.pe,YouTube\n - DOMAIN-SUFFIX,youtube.ph,YouTube\n - DOMAIN-SUFFIX,youtube.pk,YouTube\n - DOMAIN-SUFFIX,youtube.pl,YouTube\n - DOMAIN-SUFFIX,youtube.pr,YouTube\n - DOMAIN-SUFFIX,youtube.pt,YouTube\n - DOMAIN-SUFFIX,youtube.qa,YouTube\n - DOMAIN-SUFFIX,youtube.ro,YouTube\n - DOMAIN-SUFFIX,youtube.rs,YouTube\n - DOMAIN-SUFFIX,youtube.ru,YouTube\n - DOMAIN-SUFFIX,youtube.sa,YouTube\n - DOMAIN-SUFFIX,youtube.se,YouTube\n - DOMAIN-SUFFIX,youtube.sg,YouTube\n - DOMAIN-SUFFIX,youtube.si,YouTube\n - DOMAIN-SUFFIX,youtube.sk,YouTube\n - DOMAIN-SUFFIX,youtube.sn,YouTube\n - DOMAIN-SUFFIX,youtube.soy,YouTube\n - DOMAIN-SUFFIX,youtube.sv,YouTube\n - DOMAIN-SUFFIX,youtube.tn,YouTube\n - DOMAIN-SUFFIX,youtube.tv,YouTube\n - DOMAIN-SUFFIX,youtube.ua,YouTube\n - DOMAIN-SUFFIX,youtube.ug,YouTube\n - DOMAIN-SUFFIX,youtube.uy,YouTube\n - DOMAIN-SUFFIX,youtube.vn,YouTube\n - DOMAIN-SUFFIX,youtubeeducation.com,YouTube\n - DOMAIN-SUFFIX,youtubeembeddedplayer.googleapis.com,YouTube\n - DOMAIN-SUFFIX,youtubei.googleapis.com,YouTube\n - DOMAIN-SUFFIX,youtubekids.com,YouTube\n - DOMAIN-SUFFIX,youtube-nocookie.com,YouTube\n - DOMAIN-SUFFIX,youtube-ui.l.google.com,YouTube\n - DOMAIN-SUFFIX,yt.be,YouTube\n - DOMAIN-SUFFIX,yt3.ggpht.com,YouTube\n - DOMAIN-SUFFIX,ytimg.com,YouTube\n - DOMAIN-SUFFIX,max.com,Max\n - DOMAIN-SUFFIX,discomax.com,Max\n - DOMAIN-SUFFIX,arkoselabs.com,Max\n - DOMAIN-SUFFIX,brightline.tv,Max\n - DOMAIN-SUFFIX,cdn.turner.com,Max\n - DOMAIN-SUFFIX,hbo.com,Max\n - DOMAIN-SUFFIX,hbomax.com,Max\n - DOMAIN-SUFFIX,ngtv.io,Max\n - DOMAIN-SUFFIX,pypestream.com,Max\n - DOMAIN-SUFFIX,warnermediacdn.com,Max\n - DOMAIN,app-analytics-services.com,Max\n - DOMAIN,kpck4q-launches.appsflyersdk.com,Max\n - DOMAIN,kpck4q-skadsdkless.appsflyersdk.com,Max\n - DOMAIN,o0137140.ingest.us.sentry.io,Max\n - DOMAIN,out053a3bejgh7t0phqa0csou.litix.io,Max\n - DOMAIN,sdk.iad-01.braze.com,Max\n - DOMAIN-SUFFIX,branch.io,Max\n - DOMAIN-SUFFIX,acg.tv,CN Mainland TV\n - DOMAIN-SUFFIX,acgvideo.com,CN Mainland TV\n - DOMAIN-SUFFIX,b23.tv,CN Mainland TV\n - DOMAIN-SUFFIX,bilibili.com,CN Mainland TV\n - DOMAIN-SUFFIX,bilibili.tv,CN Mainland TV\n - DOMAIN-SUFFIX,biliapi.net,CN Mainland TV\n - DOMAIN-SUFFIX,biliapi.com,CN Mainland TV\n - DOMAIN-SUFFIX,bilivideo.com,CN Mainland TV\n - DOMAIN-SUFFIX,hdslb.com,CN Mainland TV\n - DOMAIN,upos-hz-mirrorakam.akamaized.net,CN Mainland TV\n - DOMAIN,apiintl.biliapi.net,CN Mainland TV\n - PROCESS-NAME,com.iqiyi.i18n,CN Mainland TV\n - PROCESS-NAME,com.iqiyi.i18n.tv,CN Mainland TV\n - DOMAIN-SUFFIX,inter.iqiyi.com,CN Mainland TV\n - DOMAIN-SUFFIX,iq.com,CN Mainland TV\n - DOMAIN-SUFFIX,intl.iqiyi.com,CN Mainland TV\n - DOMAIN,intl-rcd.iqiyi.com,CN Mainland TV\n - DOMAIN,intl-subscription.iqiyi.com,CN Mainland TV\n - IP-CIDR,104.85.165.17/32,CN Mainland TV,no-resolve\n - IP-CIDR,110.238.107.47/32,CN Mainland TV,no-resolve\n - IP-CIDR,118.26.32.162/32,CN Mainland TV,no-resolve\n - IP-CIDR,159.138.102.146/32,CN Mainland TV,no-resolve\n - IP-CIDR,184.51.102.0/24,CN Mainland TV,no-resolve\n - IP-CIDR,203.74.95.130/28,CN Mainland TV,no-resolve\n - IP-CIDR,203.80.97.203/32,CN Mainland TV,no-resolve\n - IP-CIDR,210.71.227.202/32,CN Mainland TV,no-resolve\n - IP-CIDR,23.200.145.146/32,CN Mainland TV,no-resolve\n - IP-CIDR,23.210.215.186/32,CN Mainland TV,no-resolve\n - IP-CIDR,23.211.15.0/24,CN Mainland TV,no-resolve\n - IP-CIDR,23.219.172.0/24,CN Mainland TV,no-resolve\n - IP-CIDR,23.40.242.10/32,CN Mainland TV,no-resolve\n - IP-CIDR,23.59.252.0/24,CN Mainland TV,no-resolve\n - DOMAIN-SUFFIX,iqiyi.com,CN Mainland TV\n - DOMAIN-SUFFIX,iqiyipic.com,CN Mainland TV\n - DOMAIN-SUFFIX,iq.com,CN Mainland TV\n - DOMAIN-SUFFIX,qy.net,CN Mainland TV\n - DOMAIN-SUFFIX,gitv.tv,CN Mainland TV\n - DOMAIN-SUFFIX,71.am,CN Mainland TV\n - DOMAIN-KEYWORD,qiyi,CN Mainland TV\n - DOMAIN,cache.video.iqiyi.com,CN Mainland TV\n - DOMAIN-SUFFIX,api.mob.app.letv.com,CN Mainland TV\n - DOMAIN,apm.music.163.com,CN Mainland TV\n - DOMAIN,apm3.music.163.com,CN Mainland TV\n - DOMAIN,interface.music.163.com,CN Mainland TV\n - DOMAIN,interface3.music.163.com,CN Mainland TV\n - DOMAIN,music.163.com,CN Mainland TV\n - IP-CIDR,101.71.154.241/32,CN Mainland TV,no-resolve\n - IP-CIDR,103.126.92.132/32,CN Mainland TV,no-resolve\n - IP-CIDR,103.126.92.133/32,CN Mainland TV,no-resolve\n - IP-CIDR,112.13.119.17/32,CN Mainland TV,no-resolve\n - IP-CIDR,112.13.122.1/32,CN Mainland TV,no-resolve\n - IP-CIDR,115.236.118.33/32,CN Mainland TV,no-resolve\n - IP-CIDR,115.236.121.1/32,CN Mainland TV,no-resolve\n - IP-CIDR,118.24.63.156/32,CN Mainland TV,no-resolve\n - IP-CIDR,193.112.159.225/32,CN Mainland TV,no-resolve\n - IP-CIDR,223.252.199.66/32,CN Mainland TV,no-resolve\n - IP-CIDR,223.252.199.67/32,CN Mainland TV,no-resolve\n - IP-CIDR,39.105.63.80/32,CN Mainland TV,no-resolve\n - IP-CIDR,45.254.48.1/32,CN Mainland TV,no-resolve\n - IP-CIDR,47.100.127.239/32,CN Mainland TV,no-resolve\n - IP-CIDR,59.111.160.195/32,CN Mainland TV,no-resolve\n - IP-CIDR,59.111.160.197/32,CN Mainland TV,no-resolve\n - IP-CIDR,59.111.181.35/32,CN Mainland TV,no-resolve\n - IP-CIDR,59.111.181.38/32,CN Mainland TV,no-resolve\n - IP-CIDR,59.111.181.60/32,CN Mainland TV,no-resolve\n - DOMAIN-SUFFIX,v.smtcdns.com,CN Mainland TV\n - DOMAIN-SUFFIX,vv.video.qq.com,CN Mainland TV\n - DOMAIN-SUFFIX,youku.com,CN Mainland TV\n - IP-CIDR,106.11.0.0/16,CN Mainland TV,no-resolve\n - DOMAIN-SUFFIX,wetv.vip,CN Mainland TV\n - DOMAIN-SUFFIX,wetvinfo.com,CN Mainland TV\n - DOMAIN-SUFFIX,applemusic.com,Apple TV\n - DOMAIN-SUFFIX,music.apple.com,Apple TV\n - DOMAIN,aod.itunes.apple.com,Apple TV\n - DOMAIN,aod-ssl.itunes.apple.com,Apple TV\n - DOMAIN,audio.itunes.apple.com,Apple TV\n - DOMAIN,audio-ssl.itunes.apple.com,Apple TV\n - DOMAIN,mvod.itunes.apple.com,Apple TV\n - DOMAIN,streamingaudio.itunes.apple.com,Apple TV\n - DOMAIN-SUFFIX,blobstore.apple.com,Apple TV\n - DOMAIN,gspe1-ssl.ls.apple.com,Apple TV\n - DOMAIN,np-edge.itunes.apple.com,Apple TV\n - DOMAIN,play-edge.itunes.apple.com,Apple TV\n - DOMAIN,uts-api.itunes.apple.com,Apple TV\n - DOMAIN-SUFFIX,tv.apple.com,Apple TV\n - DOMAIN-SUFFIX,abema-tv.com,Asian TV\n - DOMAIN-SUFFIX,abema.io,Asian TV\n - DOMAIN-SUFFIX,abema.tv,Asian TV\n - DOMAIN-SUFFIX,ameba.jp,Asian TV\n - DOMAIN-SUFFIX,hayabusa.io,Asian TV\n - DOMAIN-KEYWORD,abematv.akamaized.net,Asian TV\n - DOMAIN-SUFFIX,bahamut.com.tw,Asian TV\n - DOMAIN-SUFFIX,gamer.com.tw,Asian TV\n - DOMAIN,gamer-cds.cdn.hinet.net,Asian TV\n - DOMAIN,gamer2-cds.cdn.hinet.net,Asian TV\n - DOMAIN,bahamut.akamaized.net,Asian TV\n - DOMAIN-SUFFIX,akamaized.net,Asian TV\n - DOMAIN-SUFFIX,foxplus.com,Asian TV\n - DOMAIN-SUFFIX,theplatform.com,Asian TV\n - DOMAIN-SUFFIX,happyon.jp,Asian TV\n - DOMAIN-SUFFIX,hulu.jp,Asian TV\n - DOMAIN-SUFFIX,prod.hjholdings.tv,Asian TV\n - DOMAIN-SUFFIX,streaks.jp,Asian TV\n - DOMAIN-SUFFIX,yb.uncn.jp,Asian TV\n - DOMAIN-KEYWORD,japonx,Asian TV\n - DOMAIN-KEYWORD,japronx,Asian TV\n - DOMAIN-SUFFIX,japonx.com,Asian TV\n - DOMAIN-SUFFIX,japonx.tv,Asian TV\n - DOMAIN-SUFFIX,japonx.net,Asian TV\n - DOMAIN-SUFFIX,japonx.vip,Asian TV\n - DOMAIN-SUFFIX,japronx.com,Asian TV\n - DOMAIN-SUFFIX,japronx.tv,Asian TV\n - DOMAIN-SUFFIX,japronx.net,Asian TV\n - DOMAIN-SUFFIX,japronx.vip,Asian TV\n - DOMAIN-SUFFIX,joox.com,Asian TV\n - DOMAIN-SUFFIX,kkbox.com,Asian TV\n - DOMAIN-SUFFIX,kkbox.com.tw,Asian TV\n - DOMAIN-SUFFIX,kfs.io,Asian TV\n - DOMAIN-SUFFIX,kktv.me,Asian TV\n - DOMAIN-SUFFIX,kktv.com.tw,Asian TV\n - DOMAIN,kktv-theater.kk.stream,Asian TV\n - DOMAIN-SUFFIX,d3c7rimkq79yfu.cloudfront.net,Asian TV\n - DOMAIN-SUFFIX,linetv.tw,Asian TV\n - DOMAIN-SUFFIX,profile.line-scdn.net,Asian TV\n - DOMAIN-KEYWORD,nowtv100,Asian TV\n - DOMAIN-KEYWORD,rthklive,Asian TV\n - DOMAIN-SUFFIX,mytvsuper.com,Asian TV\n - DOMAIN-SUFFIX,tvb.com,Asian TV\n - DOMAIN-SUFFIX,dmc.nico,Asian TV\n - DOMAIN-SUFFIX,nicovideo.jp,Asian TV\n - DOMAIN-SUFFIX,nicodic.jp,Asian TV\n - DOMAIN-SUFFIX,nicomanga.jp,Asian TV\n - DOMAIN-SUFFIX,niconico.com,Asian TV\n - DOMAIN-SUFFIX,nicoseiga.jp,Asian TV\n - DOMAIN-SUFFIX,nimg.jp,Asian TV\n - DOMAIN-SUFFIX,simg.jp,Asian TV\n - DOMAIN-SUFFIX,socdm.com,Asian TV\n - DOMAIN-SUFFIX,bootstrapcdn.com,Asian TV\n - DOMAIN-SUFFIX,cloudfront.net,Asian TV\n - DOMAIN-SUFFIX,cognito-identity.us-east-1.amazonaws.com,Asian TV\n - DOMAIN-SUFFIX,firebaseio.com,Asian TV\n - DOMAIN-SUFFIX,jwpcdn.com,Asian TV\n - DOMAIN-SUFFIX,jwplayer.com,Asian TV\n - DOMAIN-SUFFIX,mobileanalytics.us-east-1.amazonaws.com,Asian TV\n - DOMAIN-SUFFIX,nowe.com,Asian TV\n - DOMAIN-SUFFIX,viu.com,Asian TV\n - DOMAIN-SUFFIX,viu.tv,Asian TV\n - DOMAIN-SUFFIX,viu.now.com,Asian TV\n - DOMAIN-SUFFIX,edgedatg.com,Global TV\n - DOMAIN-SUFFIX,go.com,Global TV\n - DOMAIN-KEYWORD,avoddashs,Global TV\n - DOMAIN-SUFFIX,aiv-cdn.net,Global TV\n - DOMAIN-SUFFIX,aiv-delivery.net,Global TV\n - DOMAIN-SUFFIX,amazonprimevideo.cn,Global TV\n - DOMAIN-SUFFIX,amazonprimevideo.com.cn,Global TV\n - DOMAIN-SUFFIX,amazonprimevideos.com,Global TV\n - DOMAIN-SUFFIX,amazonvideo.cc,Global TV\n - DOMAIN-SUFFIX,amazonvideo.com,Global TV\n - DOMAIN-SUFFIX,amazonvideodirect.cc,Global TV\n - DOMAIN-SUFFIX,atv-ext-eu.amazon.com,Global TV\n - DOMAIN-SUFFIX,atv-ext-fe.amazon.com,Global TV\n - DOMAIN-SUFFIX,atv-ext.amazon.com,Global TV\n - DOMAIN-SUFFIX,atv-ps-eu.amazon.co.uk,Global TV\n - DOMAIN-SUFFIX,atv-ps-eu.amazon.com,Global TV\n - DOMAIN-SUFFIX,atv-ps-fe.amazon.co.jp,Global TV\n - DOMAIN-SUFFIX,atv-ps-fe.amazon.com,Global TV\n - DOMAIN-SUFFIX,atv-ps.amazon.com,Global TV\n - DOMAIN-SUFFIX,fls-na.amazon.com,Global TV\n - DOMAIN-SUFFIX,media-amazon.com,Global TV\n - DOMAIN-SUFFIX,prime-video.com,Global TV\n - DOMAIN-SUFFIX,primevideo.cc,Global TV\n - DOMAIN-SUFFIX,primevideo.com,Global TV\n - DOMAIN-SUFFIX,primevideo.info,Global TV\n - DOMAIN-SUFFIX,primevideo.org,Global TV\n - DOMAIN-SUFFIX,primevideo.tv,Global TV\n - DOMAIN-SUFFIX,pv-cdn.net,Global TV\n - DOMAIN-SUFFIX,video.a2z.com,Global TV\n - DOMAIN,avodmp4s3ww-a.akamaihd.net,Global TV\n - DOMAIN,d1v5ir2lpwr8os.cloudfront.net,Global TV\n - DOMAIN,d1y002tclu9djj.cloudfront.net,Global TV\n - DOMAIN,d22qjgkvxw22r6.cloudfront.net,Global TV\n - DOMAIN,d25xi40x97liuc.cloudfront.net,Global TV\n - DOMAIN,dmqdd6hw24ucf.cloudfront.net,Global TV\n - DOMAIN,d27xxe7juh1us6.cloudfront.net,Global TV\n - DOMAIN,dualstack.pefs-alb-266603904.eu-west-1.elb.amazonaws.com,Global TV\n - DOMAIN-KEYWORD,-uk-live.akamaized.net,Global TV\n - DOMAIN-KEYWORD,bbcfmt,Global TV\n - DOMAIN-SUFFIX,bbc.co,Global TV\n - DOMAIN-SUFFIX,bbc.co.uk,Global TV\n - DOMAIN-SUFFIX,bbc.com,Global TV\n - DOMAIN-SUFFIX,bbcfmt.hs.llnwd.net,Global TV\n - DOMAIN-SUFFIX,bbci.co,Global TV\n - DOMAIN-SUFFIX,bbci.co.uk,Global TV\n - DOMAIN-SUFFIX,bidi.net.uk,Global TV\n - PROCESS-NAME,com.dazn,Global TV\n - DOMAIN-SUFFIX,dazn-api.com,Global TV\n - DOMAIN-SUFFIX,dazn.com,Global TV\n - DOMAIN-SUFFIX,dazndn.com,Global TV\n - DOMAIN-SUFFIX,indazn.com,Global TV\n - DOMAIN-SUFFIX,indaznlab.com,Global TV\n - DOMAIN-SUFFIX,dcalivedazn.akamaized.net,Global TV\n - DOMAIN-SUFFIX,dcblivedazn.akamaized.net,Global TV\n - DOMAIN-SUFFIX,dc1live2lindazn.akamaized.net,Global TV\n - DOMAIN-SUFFIX,dc1-lm-live2dazn.secure.footprint.net,Global TV\n - DOMAIN-SUFFIX,dc1voddazn.akamaized.net,Global TV\n - DOMAIN-SUFFIX,dc2voddazn.akamaized.net,Global TV\n - DOMAIN-SUFFIX,content-ause1-ur-discovery1.uplynk.com,Global TV\n - DOMAIN-SUFFIX,disco-api.com,Global TV\n - DOMAIN-SUFFIX,discoveryplus.com,Global TV\n - DOMAIN-SUFFIX,fwmrm.net,Global TV\n - DOMAIN-SUFFIX,getblueshift.com,Global TV\n - DOMAIN-SUFFIX,litix.io,Global TV\n - DOMAIN-SUFFIX,mobile-collector.newrelic.com,Global TV\n - DOMAIN-SUFFIX,uplynk.com,Global TV\n - DOMAIN-SUFFIX,encoretvb.com,Global TV\n - DOMAIN,content.jwplatform.com,Global TV\n - DOMAIN,videos-f.jwpsrv.com,Global TV\n - DOMAIN,d2n9h2wits23hf.cloudfront.net,Global TV\n - DOMAIN,f1prodlive.akamaized.net,Global TV\n - DOMAIN,mobile-collector.newrelic.com,Global TV\n - DOMAIN-SUFFIX,bitmovin.com,Global TV\n - DOMAIN-SUFFIX,f1esports.com,Global TV\n - DOMAIN-SUFFIX,f1manager.com,Global TV\n - DOMAIN-SUFFIX,f1play.com,Global TV\n - DOMAIN-SUFFIX,formula1.com,Global TV\n - DOMAIN-SUFFIX,fox.com,Global TV\n - DOMAIN-SUFFIX,foxdcg.com,Global TV\n - DOMAIN-SUFFIX,uplynk.com,Global TV\n - IP-CIDR,8.28.124.0/23,Global TV,no-resolve\n - IP-CIDR,199.60.116.0/24,Global TV,no-resolve\n - IP-CIDR,199.200.48.0/22,Global TV,no-resolve\n - IP-CIDR,208.91.156.0/22,Global TV,no-resolve\n - IP-CIDR6,2620:100:3000::/40,Global TV,no-resolve\n - DOMAIN-SUFFIX,hulu.com,Global TV\n - DOMAIN-SUFFIX,hulu.hb.omtrdc.net,Global TV\n - DOMAIN-SUFFIX,hulu.sc.omtrdc.net,Global TV\n - DOMAIN-SUFFIX,huluad.com,Global TV\n - DOMAIN-SUFFIX,huluim.com,Global TV\n - DOMAIN-SUFFIX,hulumail.com,Global TV\n - DOMAIN-SUFFIX,huluqa.com,Global TV\n - DOMAIN-SUFFIX,hulustream.com,Global TV\n - DOMAIN,cs428.wpc.edgecastcdn.net,Global TV\n - DOMAIN,cws-hulu.conviva.com,Global TV\n - DOMAIN,hulu.com.c.footprint.net,Global TV\n - DOMAIN,hulu.map.fastly.net,Global TV\n - DOMAIN-SUFFIX,pandora.com,Global TV\n - DOMAIN-SUFFIX,pbs.org,Global TV\n - DOMAIN-SUFFIX,phncdn.com,Global TV\n - DOMAIN-SUFFIX,phprcdn.com,Global TV\n - DOMAIN-SUFFIX,pornhub.com,Global TV\n - DOMAIN-SUFFIX,pornhubpremium.com,Global TV\n - DOMAIN-SUFFIX,sndcdn.com,Global TV\n - DOMAIN-SUFFIX,soundcloud.app.goo.gl,Global TV\n - DOMAIN-SUFFIX,soundcloud.com,Global TV\n - DOMAIN-SUFFIX,soundcloudmail.com,Global TV\n - DOMAIN-SUFFIX,t.me,Telegram\n - DOMAIN-SUFFIX,tx.me,Telegram\n - DOMAIN-SUFFIX,tdesktop.com,Telegram\n - DOMAIN-SUFFIX,telegra.ph,Telegram\n - DOMAIN-SUFFIX,telegram.me,Telegram\n - DOMAIN-SUFFIX,telegram.org,Telegram\n - DOMAIN-SUFFIX,telegram-cdn.org,Telegram\n - DOMAIN-SUFFIX,cdn-telegram.org,Telegram\n - DOMAIN-SUFFIX,telesco.pe,Telegram\n - DOMAIN-KEYWORD,telegram,Telegram\n - IP-CIDR,91.105.192.0/23,Telegram,no-resolve\n - IP-CIDR,91.108.56.0/22,Telegram,no-resolve\n - IP-CIDR,91.108.4.0/22,Telegram,no-resolve\n - IP-CIDR,91.108.8.0/22,Telegram,no-resolve\n - IP-CIDR,91.108.12.0/22,Telegram,no-resolve\n - IP-CIDR,91.108.16.0/22,Telegram,no-resolve\n - IP-CIDR,91.108.20.0/22,Telegram,no-resolve\n - IP-CIDR,95.161.64.0/20,Telegram,no-resolve\n - IP-CIDR,149.154.160.0/20,Telegram,no-resolve\n - IP-CIDR,185.76.151.0/24,Telegram,no-resolve\n - IP-CIDR6,2001:67c:4e8::/48,Telegram,no-resolve\n - IP-CIDR6,2001:b28:f23d::/48,Telegram,no-resolve\n - IP-CIDR6,2001:b28:f23f::/48,Telegram,no-resolve\n - IP-CIDR6,2a0a:f280::/32,Telegram,no-resolve\n - DOMAIN-SUFFIX,s.team,Steam\n - DOMAIN-SUFFIX,steampowered.com,Steam\n - DOMAIN-SUFFIX,steamcommunity.com,Steam\n - DOMAIN-SUFFIX,steamgames.com,Steam\n - DOMAIN-SUFFIX,steamusercontent.com,Steam\n - DOMAIN-SUFFIX,steamstatic.com,Steam\n - DOMAIN-SUFFIX,fast.com,Speedtest\n - DOMAIN-KEYWORD,speedtest,Speedtest\n - DOMAIN-SUFFIX,ooklaserver.net,Speedtest\n - DOMAIN,speed.dler.io,Speedtest\n - DOMAIN-SUFFIX,speed.cloudflare.com,Speedtest\n - DOMAIN-KEYWORD,paypal,PayPal\n - DOMAIN-SUFFIX,paypal.com,PayPal\n - DOMAIN-SUFFIX,paypalobjects.com,PayPal\n - DOMAIN-SUFFIX,here.com,Microsoft\n - DOMAIN-SUFFIX,here.net,Microsoft\n - DOMAIN-SUFFIX,heremaps.cn,Microsoft\n - DOMAIN-SUFFIX,ovi.com.cn,Microsoft\n - DOMAIN-SUFFIX,azure,Microsoft\n - DOMAIN-SUFFIX,azure-apim.net,Microsoft\n - DOMAIN-SUFFIX,azure-dns.com,Microsoft\n - DOMAIN-SUFFIX,azure-dns.info,Microsoft\n - DOMAIN-SUFFIX,azure-dns.net,Microsoft\n - DOMAIN-SUFFIX,azure-dns.org,Microsoft\n - DOMAIN-SUFFIX,azure-mobile.net,Microsoft\n - DOMAIN-SUFFIX,azure-sphere.com,Microsoft\n - DOMAIN-SUFFIX,azure-test.net,Microsoft\n - DOMAIN-SUFFIX,azure.cn,Microsoft\n - DOMAIN-SUFFIX,azure.com,Microsoft\n - DOMAIN-SUFFIX,azure.net,Microsoft\n - DOMAIN-SUFFIX,azurecomcdn.net,Microsoft\n - DOMAIN-SUFFIX,azurecontainer.io,Microsoft\n - DOMAIN-SUFFIX,azurecosmos.net,Microsoft\n - DOMAIN-SUFFIX,azurecosmosdb.com,Microsoft\n - DOMAIN-SUFFIX,azurecosmosdb.info,Microsoft\n - DOMAIN-SUFFIX,azurecosmosdb.net,Microsoft\n - DOMAIN-SUFFIX,azuredatabricks.net,Microsoft\n - DOMAIN-SUFFIX,azuredevopslaunch.com,Microsoft\n - DOMAIN-SUFFIX,azuredigitaltwin.com,Microsoft\n - DOMAIN-SUFFIX,azuredigitaltwins.com,Microsoft\n - DOMAIN-SUFFIX,azuredigitaltwins.net,Microsoft\n - DOMAIN-SUFFIX,azuredns-prd.info,Microsoft\n - DOMAIN-SUFFIX,azuredns-prd.org,Microsoft\n - DOMAIN-SUFFIX,azureedge-test.net,Microsoft\n - DOMAIN-SUFFIX,azureedge.net,Microsoft\n - DOMAIN-SUFFIX,azurefd.net,Microsoft\n - DOMAIN-SUFFIX,azurefd.us,Microsoft\n - DOMAIN-SUFFIX,azureiotcentral.com,Microsoft\n - DOMAIN-SUFFIX,azureiotsolutions.com,Microsoft\n - DOMAIN-SUFFIX,azureiotsuite.com,Microsoft\n - DOMAIN-SUFFIX,azureplanetscale.info,Microsoft\n - DOMAIN-SUFFIX,azureplanetscale.net,Microsoft\n - DOMAIN-SUFFIX,azureserviceprofiler.com,Microsoft\n - DOMAIN-SUFFIX,azuresmartspaces.net,Microsoft\n - DOMAIN-SUFFIX,azurestackvalidation.com,Microsoft\n - DOMAIN-SUFFIX,azurewebsites.net,Microsoft\n - DOMAIN-SUFFIX,chinacloudapi.cn,Microsoft\n - DOMAIN-SUFFIX,chinacloudapp.cn,Microsoft\n - DOMAIN-SUFFIX,chinacloudsites.cn,Microsoft\n - DOMAIN-SUFFIX,cosmosdb.info,Microsoft\n - DOMAIN-SUFFIX,cosmosdb.net,Microsoft\n - DOMAIN-SUFFIX,devopsms.com,Microsoft\n - DOMAIN-SUFFIX,gotcosmos.com,Microsoft\n - DOMAIN-SUFFIX,microsofteca.com,Microsoft\n - DOMAIN-SUFFIX,microsoftiotcentral.com,Microsoft\n - DOMAIN-SUFFIX,serverlesslibrary.net,Microsoft\n - DOMAIN-SUFFIX,signalr.net,Microsoft\n - DOMAIN-SUFFIX,tryfunctions.com,Microsoft\n - DOMAIN-SUFFIX,windowsazure.cn,Microsoft\n - DOMAIN-SUFFIX,windowsazure.com,Microsoft\n - DOMAIN-SUFFIX,azure.microsoft.com,Microsoft\n - DOMAIN-SUFFIX,azuremarketplace.microsoft.com,Microsoft\n - DOMAIN-SUFFIX,bbing.com,Microsoft\n - DOMAIN-SUFFIX,bibg.com,Microsoft\n - DOMAIN-SUFFIX,biing.com,Microsoft\n - DOMAIN-SUFFIX,binb.com,Microsoft\n - DOMAIN-SUFFIX,binf.com,Microsoft\n - DOMAIN-SUFFIX,bing,Microsoft\n - DOMAIN-SUFFIX,bing.com,Microsoft\n - DOMAIN-SUFFIX,bing.com.cn,Microsoft\n - DOMAIN-SUFFIX,bing.net,Microsoft\n - DOMAIN-SUFFIX,bing123.com,Microsoft\n - DOMAIN-SUFFIX,bing135.com,Microsoft\n - DOMAIN-SUFFIX,bing4.com,Microsoft\n - DOMAIN-SUFFIX,bingads.com,Microsoft\n - DOMAIN-SUFFIX,bingagencyawards.com,Microsoft\n - DOMAIN-SUFFIX,bingapis.com,Microsoft\n - DOMAIN-SUFFIX,bingapistatistics.com,Microsoft\n - DOMAIN-SUFFIX,binginternal.com,Microsoft\n - DOMAIN-SUFFIX,bingit.net,Microsoft\n - DOMAIN-SUFFIX,bingiton.com,Microsoft\n - DOMAIN-SUFFIX,bingj.com,Microsoft\n - DOMAIN-SUFFIX,bingpix.com,Microsoft\n - DOMAIN-SUFFIX,bingpk.com,Microsoft\n - DOMAIN-SUFFIX,bings.com,Microsoft\n - DOMAIN-SUFFIX,bingsandbox.com,Microsoft\n - DOMAIN-SUFFIX,bingtoolbar.com,Microsoft\n - DOMAIN-SUFFIX,bingtranslator.com,Microsoft\n - DOMAIN-SUFFIX,bingvisualsearch.com,Microsoft\n - DOMAIN-SUFFIX,bingworld.com,Microsoft\n - DOMAIN-SUFFIX,biying.cn,Microsoft\n - DOMAIN-SUFFIX,biying.com,Microsoft\n - DOMAIN-SUFFIX,biying.com.cn,Microsoft\n - DOMAIN-SUFFIX,bluehatnights.com,Microsoft\n - DOMAIN-SUFFIX,dictate.ms,Microsoft\n - DOMAIN-SUFFIX,discoverbing.com,Microsoft\n - DOMAIN-SUFFIX,explorebing.com,Microsoft\n - DOMAIN-SUFFIX,flipwithsurface.com,Microsoft\n - DOMAIN-SUFFIX,mapblast.com,Microsoft\n - DOMAIN-SUFFIX,mappoint.com,Microsoft\n - DOMAIN-SUFFIX,masalladeloslimites.com,Microsoft\n - DOMAIN-SUFFIX,microsoft-give.com,Microsoft\n - DOMAIN-SUFFIX,microsoftcloudsummit.com,Microsoft\n - DOMAIN-SUFFIX,microsoftdiplomados.com,Microsoft\n - DOMAIN-SUFFIX,microsoftlatamholiday.com,Microsoft\n - DOMAIN-SUFFIX,microsoftmxfilantropia.com,Microsoft\n - DOMAIN-SUFFIX,microsoftpartnersolutions.com,Microsoft\n - DOMAIN-SUFFIX,msnmaps.com,Microsoft\n - DOMAIN-SUFFIX,msunlimitedcloudsummit.com,Microsoft\n - DOMAIN-SUFFIX,myhomemsn.com,Microsoft\n - DOMAIN-SUFFIX,office365love.com,Microsoft\n - DOMAIN-SUFFIX,office365tw.com,Microsoft\n - DOMAIN-SUFFIX,osdinfra.net,Microsoft\n - DOMAIN-SUFFIX,renovacionoffice.com,Microsoft\n - DOMAIN-SUFFIX,sprinklesapp.com,Microsoft\n - DOMAIN-SUFFIX,working-bing-int.com,Microsoft\n - DOMAIN-SUFFIX,bj1.api.bing.com,Microsoft\n - DOMAIN-SUFFIX,emoi-cncdn.bing.com,Microsoft\n - DOMAIN-SUFFIX,cn.bing.com,Microsoft\n - DOMAIN-SUFFIX,cn.bing.net,Microsoft\n - DOMAIN-SUFFIX,ditu.live.com,Microsoft\n - DOMAIN-SUFFIX,a-msedge.net,Microsoft\n - DOMAIN-SUFFIX,c-msedge.net,Microsoft\n - DOMAIN-SUFFIX,e-msedge.net,Microsoft\n - DOMAIN-SUFFIX,edgesuite.net,Microsoft\n - DOMAIN-SUFFIX,evoke-windowsservices-tas.msedge,Microsoft\n - DOMAIN-SUFFIX,microsoftedge.com,Microsoft\n - DOMAIN-SUFFIX,microsoftedgeinsider.com,Microsoft\n - DOMAIN-SUFFIX,msedge.net,Microsoft\n - DOMAIN-SUFFIX,s-msedge.net,Microsoft\n - DOMAIN-SUFFIX,femalefounderscomp.com,Microsoft\n - DOMAIN-SUFFIX,m12.vc,Microsoft\n - DOMAIN-SUFFIX,adaptivecards.io,Microsoft\n - DOMAIN-SUFFIX,api-extractor.com,Microsoft\n - DOMAIN-SUFFIX,apisof.net,Microsoft\n - DOMAIN-SUFFIX,appcenter.ms,Microsoft\n - DOMAIN-SUFFIX,blazor.net,Microsoft\n - DOMAIN-SUFFIX,botframework.com,Microsoft\n - DOMAIN-SUFFIX,codethemicrobit.com,Microsoft\n - DOMAIN-SUFFIX,devopsassessment.net,Microsoft\n - DOMAIN-SUFFIX,dot.net,Microsoft\n - DOMAIN-SUFFIX,exp-tas.com,Microsoft\n - DOMAIN-SUFFIX,gamesstack.com,Microsoft\n - DOMAIN-SUFFIX,graphengine.io,Microsoft\n - DOMAIN-SUFFIX,insiderdevtour.com,Microsoft\n - DOMAIN-SUFFIX,jwt.ms,Microsoft\n - DOMAIN-SUFFIX,microbit.org,Microsoft\n - DOMAIN-SUFFIX,microsoftadc.com,Microsoft\n - DOMAIN-SUFFIX,microsoftgamestack.com,Microsoft\n - DOMAIN-SUFFIX,microsoftiotinsiderlabs.com,Microsoft\n - DOMAIN-SUFFIX,microsoftreactor.cn,Microsoft\n - DOMAIN-SUFFIX,microsoftreactor.com.cn,Microsoft\n - DOMAIN-SUFFIX,microsoftreactor.info,Microsoft\n - DOMAIN-SUFFIX,microsoftreactor.net,Microsoft\n - DOMAIN-SUFFIX,microsoftreactor.org,Microsoft\n - DOMAIN-SUFFIX,microsoftsilverlight.com,Microsoft\n - DOMAIN-SUFFIX,microsoftsilverlight.net,Microsoft\n - DOMAIN-SUFFIX,microsoftsilverlight.org,Microsoft\n - DOMAIN-SUFFIX,microsoftsqlserver.com,Microsoft\n - DOMAIN-SUFFIX,mmdnn.com,Microsoft\n - DOMAIN-SUFFIX,mono-project.com,Microsoft\n - DOMAIN-SUFFIX,msdn.com,Microsoft\n - DOMAIN-SUFFIX,msinnovationchallenge.com,Microsoft\n - DOMAIN-SUFFIX,mspairlift.com,Microsoft\n - DOMAIN-SUFFIX,msropendata.com,Microsoft\n - DOMAIN-SUFFIX,nuget.org,Microsoft\n - DOMAIN-SUFFIX,nugettest.org,Microsoft\n - DOMAIN-SUFFIX,opentranslatorstothings.org,Microsoft\n - DOMAIN-SUFFIX,poshtestgallery.com,Microsoft\n - DOMAIN-SUFFIX,pwabuilder.com,Microsoft\n - DOMAIN-SUFFIX,reactorms.com.cn,Microsoft\n - DOMAIN-SUFFIX,sankie.net,Microsoft\n - DOMAIN-SUFFIX,sqlserveronlinux.com,Microsoft\n - DOMAIN-SUFFIX,timelinestoryteller.com,Microsoft\n - DOMAIN-SUFFIX,uwpcommunitytoolkit.com,Microsoft\n - DOMAIN-SUFFIX,vfsforgit.com,Microsoft\n - DOMAIN-SUFFIX,vfsforgit.org,Microsoft\n - DOMAIN-SUFFIX,xamarin.com,Microsoft\n - DOMAIN-SUFFIX,developer.microsoft.com,Microsoft\n - DOMAIN-SUFFIX,dtlgalleryint.cloudapp.net,Microsoft\n - DOMAIN-SUFFIX,poshtestgallery.cloudapp.net,Microsoft\n - DOMAIN-SUFFIX,psg-int-centralus.cloudapp.net,Microsoft\n - DOMAIN-SUFFIX,psg-int-eastus.cloudapp.net,Microsoft\n - DOMAIN-SUFFIX,microsoft-online.cn,Microsoft\n - DOMAIN-SUFFIX,microsoft-online.com.cn,Microsoft\n - DOMAIN-SUFFIX,microsoftnews.cc,Microsoft\n - DOMAIN-SUFFIX,microsoftnews.cn,Microsoft\n - DOMAIN-SUFFIX,microsoftnews.com,Microsoft\n - DOMAIN-SUFFIX,microsoftnews.net,Microsoft\n - DOMAIN-SUFFIX,microsoftnews.org,Microsoft\n - DOMAIN-SUFFIX,microsoftnewsforkids.com,Microsoft\n - DOMAIN-SUFFIX,microsoftnewsforkids.net,Microsoft\n - DOMAIN-SUFFIX,microsoftnewsforkids.org,Microsoft\n - DOMAIN-SUFFIX,microsoftnewskids.com,Microsoft\n - DOMAIN-SUFFIX,microsoftnewskids.net,Microsoft\n - DOMAIN-SUFFIX,microsoftnewskids.org,Microsoft\n - DOMAIN-SUFFIX,microsoftol.com,Microsoft\n - DOMAIN-SUFFIX,microsoftol.com.cn,Microsoft\n - DOMAIN-SUFFIX,microsoftusercontent.com,Microsoft\n - DOMAIN-SUFFIX,msn.cn,Microsoft\n - DOMAIN-SUFFIX,msn.com,Microsoft\n - DOMAIN-SUFFIX,msn.com.cn,Microsoft\n - DOMAIN-SUFFIX,msn.com.nsatc.net,Microsoft\n - DOMAIN-SUFFIX,msn.com.tw,Microsoft\n - DOMAIN-SUFFIX,msnewskids.com,Microsoft\n - DOMAIN-SUFFIX,msnewskids.net,Microsoft\n - DOMAIN-SUFFIX,msnewskids.org,Microsoft\n - DOMAIN-SUFFIX,msnkids.com,Microsoft\n - DOMAIN-SUFFIX,winmp.cn,Microsoft\n - DOMAIN-SUFFIX,o365cn.com,Microsoft\n - DOMAIN-SUFFIX,o365files.cn,Microsoft\n - DOMAIN-SUFFIX,o365weve-dev.com,Microsoft\n - DOMAIN-SUFFIX,o365weve-ppe.com,Microsoft\n - DOMAIN-SUFFIX,o365weve.com,Microsoft\n - DOMAIN-SUFFIX,office,Microsoft\n - DOMAIN-SUFFIX,office.com,Microsoft\n - DOMAIN-SUFFIX,office.net,Microsoft\n - DOMAIN-SUFFIX,office365.com,Microsoft\n - DOMAIN-SUFFIX,officedev.cn,Microsoft\n - DOMAIN-SUFFIX,1drv.com,Microsoft\n - DOMAIN-SUFFIX,1drv.ms,Microsoft\n - DOMAIN-SUFFIX,livefilestore.com,Microsoft\n - DOMAIN-SUFFIX,onedrive.co,Microsoft\n - DOMAIN-SUFFIX,onedrive.co.uk,Microsoft\n - DOMAIN-SUFFIX,onedrive.com,Microsoft\n - DOMAIN-SUFFIX,onedrive.eu,Microsoft\n - DOMAIN-SUFFIX,onedrive.live.com,Microsoft\n - DOMAIN-SUFFIX,onedrive.net,Microsoft\n - DOMAIN-SUFFIX,onedrive.org,Microsoft\n - DOMAIN-SUFFIX,storage.live.com,Microsoft\n - DOMAIN-SUFFIX,groupme.com,Microsoft\n - DOMAIN-SUFFIX,skype.com,Microsoft\n - DOMAIN-SUFFIX,skype.net,Microsoft\n - DOMAIN-SUFFIX,skypeassets.com,Microsoft\n - DOMAIN-SUFFIX,skypeassets.net,Microsoft\n - DOMAIN-SUFFIX,skypeforbusiness.com,Microsoft\n - DOMAIN-SUFFIX,sway-cdn.com,Microsoft\n - DOMAIN-SUFFIX,sway-extensions.com,Microsoft\n - DOMAIN-SUFFIX,sway.com,Microsoft\n - DOMAIN-SUFFIX,visualstudio-staging.com,Microsoft\n - DOMAIN-SUFFIX,visualstudio.co,Microsoft\n - DOMAIN-SUFFIX,visualstudio.co.uk,Microsoft\n - DOMAIN-SUFFIX,visualstudio.com,Microsoft\n - DOMAIN-SUFFIX,visualstudio.eu,Microsoft\n - DOMAIN-SUFFIX,visualstudio.net,Microsoft\n - DOMAIN-SUFFIX,vsassets.io,Microsoft\n - DOMAIN-SUFFIX,vscode-unpkg.net,Microsoft\n - DOMAIN-SUFFIX,vscode-webview.net,Microsoft\n - DOMAIN-SUFFIX,vscode.dev,Microsoft\n - DOMAIN-SUFFIX,live.cn,Microsoft\n - DOMAIN-SUFFIX,live.com.akadns.net,Microsoft\n - DOMAIN-SUFFIX,sclive.net,Microsoft\n - DOMAIN-SUFFIX,windowslive.cn,Microsoft\n - DOMAIN-SUFFIX,wlxrs.com,Microsoft\n - DOMAIN-SUFFIX,aicscience.com,Microsoft\n - DOMAIN-SUFFIX,mmais.com.cn,Microsoft\n - DOMAIN-SUFFIX,msminico.cn,Microsoft\n - DOMAIN-SUFFIX,msminico.com.cn,Microsoft\n - DOMAIN-SUFFIX,msxiaobing.com,Microsoft\n - DOMAIN-SUFFIX,msxiaoice.com,Microsoft\n - DOMAIN-SUFFIX,msxiaona.cn,Microsoft\n - DOMAIN-SUFFIX,officeplus.cn,Microsoft\n - DOMAIN-SUFFIX,renlifang.com,Microsoft\n - DOMAIN-SUFFIX,cortana.ai,Microsoft\n - DOMAIN-SUFFIX,cortanaanalytics.com,Microsoft\n - DOMAIN-SUFFIX,cortanaskills.com,Microsoft\n - DOMAIN-SUFFIX,forzamotorsport.net,Microsoft\n - DOMAIN-SUFFIX,forzaracingchampionship.com,Microsoft\n - DOMAIN-SUFFIX,forzarc.com,Microsoft\n - DOMAIN-SUFFIX,gamepass.com,Microsoft\n - DOMAIN-SUFFIX,msgamestudios.com,Microsoft\n - DOMAIN-SUFFIX,orithegame.com,Microsoft\n - DOMAIN-SUFFIX,renovacionxboxlive.com,Microsoft\n - DOMAIN-SUFFIX,tellmewhygame.com,Microsoft\n - DOMAIN-SUFFIX,xbox.co,Microsoft\n - DOMAIN-SUFFIX,xbox.com,Microsoft\n - DOMAIN-SUFFIX,xbox.eu,Microsoft\n - DOMAIN-SUFFIX,xbox.org,Microsoft\n - DOMAIN-SUFFIX,xbox360.co,Microsoft\n - DOMAIN-SUFFIX,xbox360.com,Microsoft\n - DOMAIN-SUFFIX,xbox360.eu,Microsoft\n - DOMAIN-SUFFIX,xbox360.org,Microsoft\n - DOMAIN-SUFFIX,xboxab.com,Microsoft\n - DOMAIN-SUFFIX,xboxgamepass.com,Microsoft\n - DOMAIN-SUFFIX,xboxgamestudios.com,Microsoft\n - DOMAIN-SUFFIX,xboxlive.cn,Microsoft\n - DOMAIN-SUFFIX,xboxlive.com,Microsoft\n - DOMAIN-SUFFIX,xboxone.co,Microsoft\n - DOMAIN-SUFFIX,xboxone.com,Microsoft\n - DOMAIN-SUFFIX,xboxone.eu,Microsoft\n - DOMAIN-SUFFIX,xboxplayanywhere.com,Microsoft\n - DOMAIN-SUFFIX,xboxservices.com,Microsoft\n - DOMAIN-SUFFIX,xboxstudios.com,Microsoft\n - DOMAIN-SUFFIX,xbx.lv,Microsoft\n - DOMAIN-SUFFIX,callersbane.com,Microsoft\n - DOMAIN-SUFFIX,minecraft.net,Microsoft\n - DOMAIN-SUFFIX,minecraftshop.com,Microsoft\n - DOMAIN-SUFFIX,mojang.com,Microsoft\n - DOMAIN-SUFFIX,beth.games,Microsoft\n - DOMAIN-SUFFIX,bethesda.net,Microsoft\n - DOMAIN-SUFFIX,bethesdagamestudios.com,Microsoft\n - DOMAIN-SUFFIX,bethsoft.com,Microsoft\n - DOMAIN-SUFFIX,Applicationinsights.io,Microsoft\n - DOMAIN-SUFFIX,Applicationinsights.net,Microsoft\n - DOMAIN-SUFFIX,aadrm.com,Microsoft\n - DOMAIN-SUFFIX,acompli.net,Microsoft\n - DOMAIN-SUFFIX,aka.ms,Microsoft\n - DOMAIN-SUFFIX,ankarazirvesi2018.com,Microsoft\n - DOMAIN-SUFFIX,applicationinsights.io,Microsoft\n - DOMAIN-SUFFIX,applicationinsights.net,Microsoft\n - DOMAIN-SUFFIX,aria.ms,Microsoft\n - DOMAIN-SUFFIX,asp.net,Microsoft\n - DOMAIN-SUFFIX,aspnetcdn.com,Microsoft\n - DOMAIN-SUFFIX,assets-yammer.com,Microsoft\n - DOMAIN-SUFFIX,azurerms.com,Microsoft\n - DOMAIN-SUFFIX,binads.com,Microsoft\n - DOMAIN-SUFFIX,bluehatil.com,Microsoft\n - DOMAIN-SUFFIX,boswp.com,Microsoft\n - DOMAIN-SUFFIX,brazilpartneruniversity.com,Microsoft\n - DOMAIN-SUFFIX,breakdown.me,Microsoft\n - DOMAIN-SUFFIX,centralvalidation.com,Microsoft\n - DOMAIN-SUFFIX,ch9.ms,Microsoft\n - DOMAIN-SUFFIX,charticulator.com,Microsoft\n - DOMAIN-SUFFIX,cloudapp.net,Microsoft\n - DOMAIN-SUFFIX,cloudappsecurity.com,Microsoft\n - DOMAIN-SUFFIX,crmdynint-gcc.com,Microsoft\n - DOMAIN-SUFFIX,crmdynint.com,Microsoft\n - DOMAIN-SUFFIX,crossborderexpansion.com,Microsoft\n - DOMAIN-SUFFIX,docs.com,Microsoft\n - DOMAIN-SUFFIX,dwh5.com,Microsoft\n - DOMAIN-SUFFIX,dynamics.com,Microsoft\n - DOMAIN-SUFFIX,efproject.net,Microsoft\n - DOMAIN-SUFFIX,engkoo.com,Microsoft\n - DOMAIN-SUFFIX,fasttrackreadysupport.com,Microsoft\n - DOMAIN-SUFFIX,fluidpreview.com,Microsoft\n - DOMAIN-SUFFIX,footprintdns.com,Microsoft\n - DOMAIN-SUFFIX,gameuxmasterguide.com,Microsoft\n - DOMAIN-SUFFIX,gears5.com,Microsoft\n - DOMAIN-SUFFIX,gearspop.com,Microsoft\n - DOMAIN-SUFFIX,gearstactics.com,Microsoft\n - DOMAIN-SUFFIX,getmicrosoftkey.com,Microsoft\n - DOMAIN-SUFFIX,gfx.ms,Microsoft\n - DOMAIN-SUFFIX,gigjam.com,Microsoft\n - DOMAIN-SUFFIX,helpshift.com,Microsoft\n - DOMAIN-SUFFIX,hockeyapp.net,Microsoft\n - DOMAIN-SUFFIX,hololens.com,Microsoft\n - DOMAIN-SUFFIX,hotmail,Microsoft\n - DOMAIN-SUFFIX,hotmail.co,Microsoft\n - DOMAIN-SUFFIX,hotmail.com,Microsoft\n - DOMAIN-SUFFIX,hotmail.eu,Microsoft\n - DOMAIN-SUFFIX,hotmail.net,Microsoft\n - DOMAIN-SUFFIX,hotmail.org,Microsoft\n - DOMAIN-SUFFIX,hummingbird.ms,Microsoft\n - DOMAIN-SUFFIX,ie10.com,Microsoft\n - DOMAIN-SUFFIX,ie11.com,Microsoft\n - DOMAIN-SUFFIX,ie8.co,Microsoft\n - DOMAIN-SUFFIX,ie9.com,Microsoft\n - DOMAIN-SUFFIX,imaginecup.pl,Microsoft\n - DOMAIN-SUFFIX,img-prod-cms-rt-microsoft-com,Microsoft\n - DOMAIN-SUFFIX,ingads.com,Microsoft\n - DOMAIN-SUFFIX,internetexplorer.co,Microsoft\n - DOMAIN-SUFFIX,internetexplorer.com,Microsoft\n - DOMAIN-SUFFIX,intunewiki.com,Microsoft\n - DOMAIN-SUFFIX,iotinactionevents.com,Microsoft\n - DOMAIN-SUFFIX,joinms.com,Microsoft\n - DOMAIN-SUFFIX,joinms.com.cn,Microsoft\n - DOMAIN-SUFFIX,joinmva.com,Microsoft\n - DOMAIN-SUFFIX,kidgrid.tv,Microsoft\n - DOMAIN-SUFFIX,kumo.com,Microsoft\n - DOMAIN-SUFFIX,latampartneruniversity.com,Microsoft\n - DOMAIN-SUFFIX,live.com,Microsoft\n - DOMAIN-SUFFIX,live.com.au,Microsoft\n - DOMAIN-SUFFIX,live.eu,Microsoft\n - DOMAIN-SUFFIX,live.net,Microsoft\n - DOMAIN-SUFFIX,livingyourambition.com,Microsoft\n - DOMAIN-SUFFIX,localytics.com,Microsoft\n - DOMAIN-SUFFIX,lync.com,Microsoft\n - DOMAIN-SUFFIX,makecode.org,Microsoft\n - DOMAIN-SUFFIX,managedmeetingrooms.com,Microsoft\n - DOMAIN-SUFFIX,meetfasttrack.com,Microsoft\n - DOMAIN-SUFFIX,meetyourdevices.com,Microsoft\n - DOMAIN-SUFFIX,mepn.com,Microsoft\n - DOMAIN-SUFFIX,microsoft,Microsoft\n - DOMAIN-SUFFIX,microsoft-int.com,Microsoft\n - DOMAIN-SUFFIX,microsoft-ppe.com,Microsoft\n - DOMAIN-SUFFIX,microsoft-sap-events.com,Microsoft\n - DOMAIN-SUFFIX,microsoft-sbs-domains.com,Microsoft\n - DOMAIN-SUFFIX,microsoft-smb.cn,Microsoft\n - DOMAIN-SUFFIX,microsoft.az,Microsoft\n - DOMAIN-SUFFIX,microsoft.be,Microsoft\n - DOMAIN-SUFFIX,microsoft.by,Microsoft\n - DOMAIN-SUFFIX,microsoft.ca,Microsoft\n - DOMAIN-SUFFIX,microsoft.cat,Microsoft\n - DOMAIN-SUFFIX,microsoft.ch,Microsoft\n - DOMAIN-SUFFIX,microsoft.cl,Microsoft\n - DOMAIN-SUFFIX,microsoft.com,Microsoft\n - DOMAIN-SUFFIX,microsoft.com.akadns.net,Microsoft\n - DOMAIN-SUFFIX,microsoft.com.nsatc.net,Microsoft\n - DOMAIN-SUFFIX,microsoft.cz,Microsoft\n - DOMAIN-SUFFIX,microsoft.de,Microsoft\n - DOMAIN-SUFFIX,microsoft.dk,Microsoft\n - DOMAIN-SUFFIX,microsoft.ee,Microsoft\n - DOMAIN-SUFFIX,microsoft.es,Microsoft\n - DOMAIN-SUFFIX,microsoft.eu,Microsoft\n - DOMAIN-SUFFIX,microsoft.fi,Microsoft\n - DOMAIN-SUFFIX,microsoft.ge,Microsoft\n - DOMAIN-SUFFIX,microsoft.hu,Microsoft\n - DOMAIN-SUFFIX,microsoft.io,Microsoft\n - DOMAIN-SUFFIX,microsoft.is,Microsoft\n - DOMAIN-SUFFIX,microsoft.it,Microsoft\n - DOMAIN-SUFFIX,microsoft.jp,Microsoft\n - DOMAIN-SUFFIX,microsoft.lt,Microsoft\n - DOMAIN-SUFFIX,microsoft.lu,Microsoft\n - DOMAIN-SUFFIX,microsoft.lv,Microsoft\n - DOMAIN-SUFFIX,microsoft.md,Microsoft\n - DOMAIN-SUFFIX,microsoft.net,Microsoft\n - DOMAIN-SUFFIX,microsoft.pl,Microsoft\n - DOMAIN-SUFFIX,microsoft.pt,Microsoft\n - DOMAIN-SUFFIX,microsoft.red,Microsoft\n - DOMAIN-SUFFIX,microsoft.ro,Microsoft\n - DOMAIN-SUFFIX,microsoft.rs,Microsoft\n - DOMAIN-SUFFIX,microsoft.ru,Microsoft\n - DOMAIN-SUFFIX,microsoft.se,Microsoft\n - DOMAIN-SUFFIX,microsoft.si,Microsoft\n - DOMAIN-SUFFIX,microsoft.tv,Microsoft\n - DOMAIN-SUFFIX,microsoft.ua,Microsoft\n - DOMAIN-SUFFIX,microsoft.uz,Microsoft\n - DOMAIN-SUFFIX,microsoft.vn,Microsoft\n - DOMAIN-SUFFIX,microsoft365.com,Microsoft\n - DOMAIN-SUFFIX,microsoftaccountguard.com,Microsoft\n - DOMAIN-SUFFIX,microsoftads.com,Microsoft\n - DOMAIN-SUFFIX,microsoftadvertising.com,Microsoft\n - DOMAIN-SUFFIX,microsoftadvertisingregionalawards.com,Microsoft\n - DOMAIN-SUFFIX,microsoftaffiliates.com,Microsoft\n - DOMAIN-SUFFIX,microsoftapps.azurewebsites.net,Microsoft\n - DOMAIN-SUFFIX,microsoftazuread-sso.com,Microsoft\n - DOMAIN-SUFFIX,microsoftcloud.com,Microsoft\n - DOMAIN-SUFFIX,microsoftcloudworkshop.com,Microsoft\n - DOMAIN-SUFFIX,microsoftcommunitytraining.com,Microsoft\n - DOMAIN-SUFFIX,microsoftemail.com,Microsoft\n - DOMAIN-SUFFIX,microsoftestore.com.hk,Microsoft\n - DOMAIN-SUFFIX,microsofthouse.com,Microsoft\n - DOMAIN-SUFFIX,microsofthouse.net,Microsoft\n - DOMAIN-SUFFIX,microsoftinternetsafety.net,Microsoft\n - DOMAIN-SUFFIX,microsoftlatamaitour.com,Microsoft\n - DOMAIN-SUFFIX,microsoftlinc.com,Microsoft\n - DOMAIN-SUFFIX,microsoftonline-p.com,Microsoft\n - DOMAIN-SUFFIX,microsoftonline-p.net,Microsoft\n - DOMAIN-SUFFIX,microsoftonline.com,Microsoft\n - DOMAIN-SUFFIX,microsoftpartnercommunity.com,Microsoft\n - DOMAIN-SUFFIX,microsoftready.com,Microsoft\n - DOMAIN-SUFFIX,microsoftsiteselection.com,Microsoft\n - DOMAIN-SUFFIX,microsoftstore.com,Microsoft\n - DOMAIN-SUFFIX,microsoftstore.com.cn,Microsoft\n - DOMAIN-SUFFIX,microsoftstore.com.hk,Microsoft\n - DOMAIN-SUFFIX,microsoftstream.com,Microsoft\n - DOMAIN-SUFFIX,microsoftteams.com,Microsoft\n - DOMAIN-SUFFIX,microsofttradein.com,Microsoft\n - DOMAIN-SUFFIX,microsofttranslator.com,Microsoft\n - DOMAIN-SUFFIX,microsoftuwp.com,Microsoft\n - DOMAIN-SUFFIX,momentumms.com,Microsoft\n - DOMAIN-SUFFIX,morphcharts.com,Microsoft\n - DOMAIN-SUFFIX,mpnevolution.com,Microsoft\n - DOMAIN-SUFFIX,ms-studiosmedia.com,Microsoft\n - DOMAIN-SUFFIX,ms365surfaceoffer.com,Microsoft\n - DOMAIN-SUFFIX,msa.akadns6.net,Microsoft\n - DOMAIN-SUFFIX,msads.net,Microsoft\n - DOMAIN-SUFFIX,msappproxy.net,Microsoft\n - DOMAIN-SUFFIX,msauth.cn,Microsoft\n - DOMAIN-SUFFIX,msauth.net,Microsoft\n - DOMAIN-SUFFIX,msauthimages.net,Microsoft\n - DOMAIN-SUFFIX,mschallenge2018.com,Microsoft\n - DOMAIN-SUFFIX,msecnd.net,Microsoft\n - DOMAIN-SUFFIX,msft.info,Microsoft\n - DOMAIN-SUFFIX,msft.net,Microsoft\n - DOMAIN-SUFFIX,msftauth.cn,Microsoft\n - DOMAIN-SUFFIX,msftauth.net,Microsoft\n - DOMAIN-SUFFIX,msftauthimages.net,Microsoft\n - DOMAIN-SUFFIX,msftcenterone.cn,Microsoft\n - DOMAIN-SUFFIX,msftconnecttest.com,Microsoft\n - DOMAIN-SUFFIX,msfteducation.ca,Microsoft\n - DOMAIN-SUFFIX,msftidentity.com,Microsoft\n - DOMAIN-SUFFIX,msftnet.org,Microsoft\n - DOMAIN-SUFFIX,msgamesresearch.com,Microsoft\n - DOMAIN-SUFFIX,msidentity.com,Microsoft\n - DOMAIN-SUFFIX,msignitechina.com,Microsoft\n - DOMAIN-SUFFIX,msocdn.com,Microsoft\n - DOMAIN-SUFFIX,msocsp.com,Microsoft\n - DOMAIN-SUFFIX,msopentech.cn,Microsoft\n - DOMAIN-SUFFIX,mspil.cn,Microsoft\n - DOMAIN-SUFFIX,msra.cn,Microsoft\n - DOMAIN-SUFFIX,mstea.ms,Microsoft\n - DOMAIN-SUFFIX,msturing.org,Microsoft\n - DOMAIN-SUFFIX,msudalosti.com,Microsoft\n - DOMAIN-SUFFIX,msvevent.com,Microsoft\n - DOMAIN-SUFFIX,mymicrosoft.com,Microsoft\n - DOMAIN-SUFFIX,nextechafrica.net,Microsoft\n - DOMAIN-SUFFIX,nxta.org,Microsoft\n - DOMAIN-SUFFIX,oaspapps.com,Microsoft\n - DOMAIN-SUFFIX,oaspapps.com.akadns.net,Microsoft\n - DOMAIN-SUFFIX,onecollector.cloudapp.aria,Microsoft\n - DOMAIN-SUFFIX,onecollector.cloudapp.aria.akadns.net,Microsoft\n - DOMAIN-SUFFIX,onenote.com,Microsoft\n - DOMAIN-SUFFIX,onenote.net,Microsoft\n - DOMAIN-SUFFIX,onestore.ms,Microsoft\n - DOMAIN-SUFFIX,onmicrosoft.com,Microsoft\n - DOMAIN-SUFFIX,opticsforthecloud.net,Microsoft\n - DOMAIN-SUFFIX,optimizely.com,Microsoft\n - DOMAIN-SUFFIX,outingsapp.com,Microsoft\n - DOMAIN-SUFFIX,outlook.cn,Microsoft\n - DOMAIN-SUFFIX,outlook.com,Microsoft\n - DOMAIN-SUFFIX,outlookgroups.ms,Microsoft\n - DOMAIN-SUFFIX,outlookmobile.com,Microsoft\n - DOMAIN-SUFFIX,passport.net,Microsoft\n - DOMAIN-SUFFIX,phonefactor.net,Microsoft\n - DOMAIN-SUFFIX,pixapp.net,Microsoft\n - DOMAIN-SUFFIX,playfabapi.cn,Microsoft\n - DOMAIN-SUFFIX,playfabcn.com,Microsoft\n - DOMAIN-SUFFIX,powerappscdn.net,Microsoft\n - DOMAIN-SUFFIX,powerautomate.com,Microsoft\n - DOMAIN-SUFFIX,powerbi.com,Microsoft\n - DOMAIN-SUFFIX,powershellgallery.com,Microsoft\n - DOMAIN-SUFFIX,projectmurphy.net,Microsoft\n - DOMAIN-SUFFIX,projectsangam.com,Microsoft\n - DOMAIN-SUFFIX,pxt.io,Microsoft\n - DOMAIN-SUFFIX,s-microsoft.com,Microsoft\n - DOMAIN-SUFFIX,s-msft.com,Microsoft\n - DOMAIN-SUFFIX,s-msn.com,Microsoft\n - DOMAIN-SUFFIX,sfbassets.com,Microsoft\n - DOMAIN-SUFFIX,sfbassets.net,Microsoft\n - DOMAIN-SUFFIX,sfx.ms,Microsoft\n - DOMAIN-SUFFIX,sharepoint.cn,Microsoft\n - DOMAIN-SUFFIX,sharepoint.com,Microsoft\n - DOMAIN-SUFFIX,sharepointonline.com,Microsoft\n - DOMAIN-SUFFIX,skype,Microsoft\n - DOMAIN-SUFFIX,staffhub.ms,Microsoft\n - DOMAIN-SUFFIX,successwithteams.com,Microsoft\n - DOMAIN-SUFFIX,surface.com,Microsoft\n - DOMAIN-SUFFIX,svc.ms,Microsoft\n - DOMAIN-SUFFIX,syncshop.cn,Microsoft\n - DOMAIN-SUFFIX,sysinternals.com,Microsoft\n - DOMAIN-SUFFIX,tailwindtraders.com,Microsoft\n - DOMAIN-SUFFIX,techhub.ms,Microsoft\n - DOMAIN-SUFFIX,tenor.com,Microsoft\n - DOMAIN-SUFFIX,tfsallin.net,Microsoft\n - DOMAIN-SUFFIX,trafficmanager.net,Microsoft\n - DOMAIN-SUFFIX,translatetheweb.com,Microsoft\n - DOMAIN-SUFFIX,unlocklimitlesslearning.com,Microsoft\n - DOMAIN-SUFFIX,userpxt.io,Microsoft\n - DOMAIN-SUFFIX,uservoice.com,Microsoft\n - DOMAIN-SUFFIX,videobreakdown.com,Microsoft\n - DOMAIN-SUFFIX,videoindexer.ai,Microsoft\n - DOMAIN-SUFFIX,virtualearth.net,Microsoft\n - DOMAIN-SUFFIX,vsallin.net,Microsoft\n - DOMAIN-SUFFIX,wbd.ms,Microsoft\n - DOMAIN-SUFFIX,what-fan.net,Microsoft\n - DOMAIN-SUFFIX,windows.com,Microsoft\n - DOMAIN-SUFFIX,windows.net,Microsoft\n - DOMAIN-SUFFIX,windows-int.net,Microsoft\n - DOMAIN-SUFFIX,windows-ppe.net,Microsoft\n - DOMAIN-SUFFIX,windows.com,Microsoft\n - DOMAIN-SUFFIX,windows.net,Microsoft\n - DOMAIN-SUFFIX,windows.nl,Microsoft\n - DOMAIN-SUFFIX,windows8.hk,Microsoft\n - DOMAIN-SUFFIX,windowscommunity.net,Microsoft\n - DOMAIN-SUFFIX,windowsmarketplace.com,Microsoft\n - DOMAIN-SUFFIX,windowsphone-int.com,Microsoft\n - DOMAIN-SUFFIX,windowsphone.com,Microsoft\n - DOMAIN-SUFFIX,windowssearch.com,Microsoft\n - DOMAIN-SUFFIX,windowsupdate.com,Microsoft\n - DOMAIN-SUFFIX,winhec.com,Microsoft\n - DOMAIN-SUFFIX,winhec.net,Microsoft\n - DOMAIN-SUFFIX,yammer.com,Microsoft\n - DOMAIN-SUFFIX,yammerusercontent.com,Microsoft\n - DOMAIN-SUFFIX,g.akamaiedge.net,Microsoft\n - DOMAIN-SUFFIX,a1158.g.akamai.net,Microsoft\n - DOMAIN-SUFFIX,a122.dscg3.akamai.net,Microsoft\n - DOMAIN-SUFFIX,a767.dscg3.akamai.net,Microsoft\n - DOMAIN-SUFFIX,cs11.wpc.v0cdn.net,Microsoft\n - DOMAIN-SUFFIX,cs9.wac.phicdn.net,Microsoft\n - DOMAIN-SUFFIX,b.akamaiedge.net,Microsoft\n - DOMAIN-SUFFIX,spoprod-a.akamaihd.net,Microsoft\n - DOMAIN-SUFFIX,windows.com.akadns.net,Microsoft\n - DOMAIN-SUFFIX,prod-video-cms-rt-microsoft-com.akamaized.net,Microsoft\n - DOMAIN-SUFFIX,statics-marketingsites-eas-ms-com.akamaized.net,Microsoft\n - DOMAIN-SUFFIX,statics-marketingsites-neu-ms-com.akamaized.net,Microsoft\n - DOMAIN-SUFFIX,vip5.afdorigin-prod-am02.afdogw.com,Microsoft\n - DOMAIN-SUFFIX,img-prod-cms-rt-microsoft-com.akamaized.net,Microsoft\n - DOMAIN-SUFFIX,img-s-msn-com.akamaized.net,Microsoft\n - DOMAIN-SUFFIX,mwf-service.akamaized.net,Microsoft\n - DOMAIN-SUFFIX,officecdn-microsoft-com.akamaized.net,Microsoft\n - DOMAIN-SUFFIX,statics-marketingsites-eus-ms-com.akamaized.net,Microsoft\n - DOMAIN-SUFFIX,statics-marketingsites-wcus-ms-com.akamaized.net,Microsoft\n - DOMAIN,apm.music.163.com,Netease Music\n - DOMAIN,apm3.music.163.com,Netease Music\n - DOMAIN,interface.music.163.com,Netease Music\n - DOMAIN,interface3.music.163.com,Netease Music\n - DOMAIN,music.163.com,Netease Music\n - IP-CIDR,101.71.154.241/32,Netease Music,no-resolve\n - IP-CIDR,103.126.92.132/32,Netease Music,no-resolve\n - IP-CIDR,103.126.92.133/32,Netease Music,no-resolve\n - IP-CIDR,112.13.119.17/32,Netease Music,no-resolve\n - IP-CIDR,112.13.122.1/32,Netease Music,no-resolve\n - IP-CIDR,115.236.118.33/32,Netease Music,no-resolve\n - IP-CIDR,115.236.121.1/32,Netease Music,no-resolve\n - IP-CIDR,118.24.63.156/32,Netease Music,no-resolve\n - IP-CIDR,193.112.159.225/32,Netease Music,no-resolve\n - IP-CIDR,223.252.199.66/32,Netease Music,no-resolve\n - IP-CIDR,223.252.199.67/32,Netease Music,no-resolve\n - IP-CIDR,39.105.63.80/32,Netease Music,no-resolve\n - IP-CIDR,45.254.48.1/32,Netease Music,no-resolve\n - IP-CIDR,47.100.127.239/32,Netease Music,no-resolve\n - IP-CIDR,59.111.160.195/32,Netease Music,no-resolve\n - IP-CIDR,59.111.160.197/32,Netease Music,no-resolve\n - IP-CIDR,59.111.181.35/32,Netease Music,no-resolve\n - IP-CIDR,59.111.181.38/32,Netease Music,no-resolve\n - IP-CIDR,59.111.181.60/32,Netease Music,no-resolve\n - PROCESS-NAME,storedownloadd,DIRECT\n - DOMAIN,aod.itunes.apple.com,DIRECT\n - DOMAIN,api.smoot.apple.cn,DIRECT\n - DOMAIN,appldnld.apple.com,DIRECT\n - DOMAIN,apptrailers.itunes.apple.com,DIRECT\n - DOMAIN,gs-loc-cn.apple.com,DIRECT\n - DOMAIN,iosapps.itunes.apple.com,DIRECT\n - DOMAIN,music.apple.com,DIRECT\n - DOMAIN,mvod.itunes.apple.com,DIRECT\n - DOMAIN,osxapps.itunes.apple.com,DIRECT\n - DOMAIN,supportdownload.apple.com,DIRECT\n - DOMAIN,swcdn.apple.com,DIRECT\n - DOMAIN,updates-http.cdn-apple.com,DIRECT\n - DOMAIN-SUFFIX,ls.apple.com,DIRECT\n - DOMAIN-KEYWORD,epicgames,DIRECT\n - DOMAIN,safebrowsing.googleapis.com,DIRECT\n - DOMAIN-SUFFIX,dl.google.com,DIRECT\n - DOMAIN-SUFFIX,msftconnecttest.com,DIRECT\n - PROCESS-NAME,v2ray,DIRECT\n - PROCESS-NAME,ss-local,DIRECT\n - DOMAIN-SUFFIX,dl.playstation.net,DIRECT\n - DOMAIN,cm.steampowered.com,DIRECT\n - DOMAIN,ol.epicgames.com,DIRECT\n - DOMAIN-SUFFIX,steamcontent.com,DIRECT\n - DOMAIN-SUFFIX,steamserver.net,DIRECT\n - DOMAIN-SUFFIX,steamchina.com,DIRECT\n - DOMAIN,csgo.wmsj.cn,DIRECT\n - DOMAIN,dota2.wmsj.cn,DIRECT\n - DOMAIN,wmsjsteam.com,DIRECT\n - DOMAIN,dl.steam.clngaa.com,DIRECT\n - DOMAIN,dl.steam.ksyna.com,DIRECT\n - DOMAIN,gstore.val.manlaxy.com,DIRECT\n - DOMAIN,st.dl.bscstorage.net,DIRECT\n - DOMAIN,st.dl.eccdnx.com,DIRECT\n - DOMAIN,st.dl.pinyuncloud.com,DIRECT\n - DOMAIN,steampipe.steamcontent.tnkjmec.com,DIRECT\n - DOMAIN,steampowered.com.8686c.com,DIRECT\n - DOMAIN,steamstatic.com.8686c.com,DIRECT\n - DOMAIN,steambroadcast.akamaized.net,DIRECT\n - DOMAIN,steamcdn-a.akamaihd.net,DIRECT\n - DOMAIN,steamcommunity-a.akamaihd.net,DIRECT\n - DOMAIN,steamstore-a.akamaihd.net,DIRECT\n - DOMAIN,steamusercontent-a.akamaihd.net,DIRECT\n - DOMAIN,steamuserimages-a.akamaihd.net,DIRECT\n - DOMAIN,tesla-cdn.thron.cn,DIRECT\n - DOMAIN,tesla-cdn.thron.com,DIRECT\n - DOMAIN-SUFFIX,solarcity.com,DIRECT\n - DOMAIN-SUFFIX,tesla.cn,DIRECT\n - DOMAIN-SUFFIX,tesla.com,DIRECT\n - DOMAIN-SUFFIX,tesla.com.cn,DIRECT\n - DOMAIN-SUFFIX,teslamotors.cn,DIRECT\n - DOMAIN-SUFFIX,teslamotors.com,DIRECT\n - DOMAIN-SUFFIX,teslamotors.com.cn,DIRECT\n - DOMAIN-SUFFIX,ts.la,DIRECT\n - PROCESS-NAME,UUBooster,DIRECT\n - DOMAIN-SUFFIX,app-measurement.com,DIRECT\n - DOMAIN-SUFFIX,xunlei.com,DIRECT\n - PROCESS-NAME,aria2c,DIRECT\n - PROCESS-NAME,fdm,DIRECT\n - PROCESS-NAME,Folx,DIRECT\n - PROCESS-NAME,NetTransport,DIRECT\n - PROCESS-NAME,qbittorrent,DIRECT\n - PROCESS-NAME,qbittorrent-nox,DIRECT\n - PROCESS-NAME,Thunder,DIRECT\n - PROCESS-NAME,Transmission,DIRECT\n - PROCESS-NAME,uTorrent,DIRECT\n - PROCESS-NAME,WebTorrent,DIRECT\n - PROCESS-NAME,WebTorrent Helper,DIRECT\n - DOMAIN-SUFFIX,audiences.me,DIRECT\n - DOMAIN-SUFFIX,awesome-hd.me,DIRECT\n - DOMAIN-SUFFIX,broadcasthe.net,DIRECT\n - DOMAIN-SUFFIX,chdbits.co,DIRECT\n - DOMAIN-SUFFIX,classix-unlimited.co.uk,DIRECT\n - DOMAIN-SUFFIX,dmhy.best,DIRECT\n - DOMAIN-SUFFIX,empornium.me,DIRECT\n - DOMAIN-SUFFIX,gazellegames.net,DIRECT\n - DOMAIN-SUFFIX,hdchina.org,DIRECT\n - DOMAIN-SUFFIX,hdsky.me,DIRECT\n - DOMAIN-SUFFIX,icetorrent.org,DIRECT\n - DOMAIN-SUFFIX,jpopsuki.eu,DIRECT\n - DOMAIN-SUFFIX,keepfrds.com,DIRECT\n - DOMAIN-SUFFIX,madsrevolution.net,DIRECT\n - DOMAIN-SUFFIX,m-team.cc,DIRECT\n - DOMAIN-SUFFIX,nanyangpt.com,DIRECT\n - DOMAIN-SUFFIX,ncore.cc,DIRECT\n - DOMAIN-SUFFIX,open.cd,DIRECT\n - DOMAIN-SUFFIX,ourbits.club,DIRECT\n - DOMAIN-SUFFIX,passthepopcorn.me,DIRECT\n - DOMAIN-SUFFIX,privatehd.to,DIRECT\n - DOMAIN-SUFFIX,redacted.ch,DIRECT\n - DOMAIN-SUFFIX,sandai.net,DIRECT\n - DOMAIN-SUFFIX,springsunday.net,DIRECT\n - DOMAIN-SUFFIX,tjupt.org,DIRECT\n - DOMAIN-SUFFIX,totheglory.im,DIRECT\n - DOMAIN-SUFFIX,smtp,DIRECT\n - DOMAIN,uplaypc-s-ubisoft.cdn.ubi.com,DIRECT\n - IP-CIDR,100.64.0.0/10,DIRECT,no-resolve\n - DOMAIN,testflight.apple.com,Proxies\n - DOMAIN,cdp.cloud.unity3d.com,Proxies\n - DOMAIN-SUFFIX,battle.net,Proxies\n - DOMAIN-SUFFIX,battlenet.com,Proxies\n - DOMAIN-SUFFIX,blizzard.com,Proxies\n - DOMAIN-SUFFIX,lin.ee,Proxies\n - DOMAIN-SUFFIX,line.me,Proxies\n - DOMAIN-SUFFIX,line.naver.jp,Proxies\n - DOMAIN-SUFFIX,line-apps.com,Proxies\n - DOMAIN-SUFFIX,line-cdn.net,Proxies\n - DOMAIN-SUFFIX,line-scdn.net,Proxies\n - DOMAIN-SUFFIX,nhncorp.jp,Proxies\n - DOMAIN-SUFFIX,riotcdn.net,Proxies\n - DOMAIN-SUFFIX,wr.pvp.net,Proxies\n - DOMAIN-SUFFIX,riotgames.com,Proxies\n - DOMAIN-SUFFIX,playstation.com,Proxies\n - DOMAIN-SUFFIX,playstation.net,Proxies\n - DOMAIN-SUFFIX,playstationnetwork.com,Proxies\n - DOMAIN-SUFFIX,api.amplitude.com,Proxies\n - DOMAIN-SUFFIX,app.smartmailcloud.com,Proxies\n - DOMAIN-SUFFIX,gate.hockeyapp.net,Proxies\n - DOMAIN-SUFFIX,smartmailcloud.com,Proxies\n - DOMAIN-KEYWORD,tesla,Proxies\n - DOMAIN,api.waqi.info,Proxies\n - DOMAIN,aqi.aqicn.org,Proxies\n - DOMAIN-SUFFIX,2o7.net,Proxies\n - DOMAIN-SUFFIX,4everProxy.com,Proxies\n - DOMAIN-SUFFIX,4shared.com,Proxies\n - DOMAIN-SUFFIX,4sqi.net,Proxies\n - DOMAIN-SUFFIX,9to5mac.com,Proxies\n - DOMAIN-SUFFIX,abpchina.org,Proxies\n - DOMAIN-SUFFIX,accountkit.com,Proxies\n - DOMAIN-SUFFIX,adblockplus.org,Proxies\n - DOMAIN-SUFFIX,adobe.com,Proxies\n - DOMAIN-SUFFIX,adobedtm.com,Proxies\n - DOMAIN-SUFFIX,aerisapi.com,Proxies\n - DOMAIN-SUFFIX,akamaihd.net,Proxies\n - DOMAIN-SUFFIX,airtable.com,Proxies\n - DOMAIN-SUFFIX,alfredapp.com,Proxies\n - DOMAIN-SUFFIX,allconnected.co,Proxies\n - DOMAIN-SUFFIX,amazon.co,Proxies\n - DOMAIN-SUFFIX,amazon.co.jp,Proxies\n - DOMAIN-SUFFIX,amazon.com,Proxies\n - DOMAIN-SUFFIX,amazonaws.com,Proxies\n - DOMAIN-SUFFIX,ampproject.com,Proxies\n - DOMAIN-SUFFIX,ampproject.net,Proxies\n - DOMAIN-SUFFIX,ampproject.org,Proxies\n - DOMAIN-SUFFIX,anaconda.com,Proxies\n - DOMAIN-SUFFIX,ancsconf.org,Proxies\n - DOMAIN-SUFFIX,android.com,Proxies\n - DOMAIN-SUFFIX,androidify.com,Proxies\n - DOMAIN-SUFFIX,android-x86.org,Proxies\n - DOMAIN-SUFFIX,angularjs.org,Proxies\n - DOMAIN-SUFFIX,anthonycalzadilla.com,Proxies\n - DOMAIN-SUFFIX,aol.com,Proxies\n - DOMAIN-SUFFIX,aolcdn.com,Proxies\n - DOMAIN-SUFFIX,apache.org,Proxies\n - DOMAIN-SUFFIX,api.mixpanel.com,Proxies\n - DOMAIN-SUFFIX,api.termius.com,Proxies\n - DOMAIN-SUFFIX,api.tiktokv.com,Proxies\n - DOMAIN-SUFFIX,api.urbandictionary.com,Proxies\n - DOMAIN-SUFFIX,apigee.com,Proxies\n - DOMAIN-SUFFIX,apk-dl.com,Proxies\n - DOMAIN-SUFFIX,apkpure.com,Proxies\n - DOMAIN-SUFFIX,appdownloader.net,Proxies\n - DOMAIN-SUFFIX,apple-dns.net,Proxies\n - DOMAIN-SUFFIX,appshopper.com,Proxies\n - DOMAIN-SUFFIX,arcgis.com,Proxies\n - DOMAIN-SUFFIX,archive.is,Proxies\n - DOMAIN-SUFFIX,archive.org,Proxies\n - DOMAIN-SUFFIX,archives.gov,Proxies\n - DOMAIN-SUFFIX,armorgames.com,Proxies\n - DOMAIN-SUFFIX,aspnetcdn.com,Proxies\n - DOMAIN-SUFFIX,async.be,Proxies\n - DOMAIN-SUFFIX,att.com,Proxies\n - DOMAIN-SUFFIX,avgle.com,Proxies\n - DOMAIN-SUFFIX,awsstatic.com,Proxies\n - DOMAIN-SUFFIX,azure.com,Proxies\n - DOMAIN-SUFFIX,azureedge.net,Proxies\n - DOMAIN-SUFFIX,azurewebsites.net,Proxies\n - DOMAIN-SUFFIX,badoo.com,Proxies\n - DOMAIN-SUFFIX,bandisoft.com,Proxies\n - DOMAIN-SUFFIX,bbtoystore.com,Proxies\n - DOMAIN-SUFFIX,bet365.com,Proxies\n - DOMAIN-SUFFIX,betvictor.com,Proxies\n - DOMAIN-SUFFIX,bigsound.org,Proxies\n - DOMAIN-SUFFIX,bintray.com,Proxies\n - DOMAIN-SUFFIX,bit.com,Proxies\n - DOMAIN-SUFFIX,bit.do,Proxies\n - DOMAIN-SUFFIX,bit.ly,Proxies\n - DOMAIN-SUFFIX,bitbucket.org,Proxies\n - DOMAIN-SUFFIX,bitcointalk.org,Proxies\n - DOMAIN-SUFFIX,bitshare.com,Proxies\n - DOMAIN-SUFFIX,bkrtx.com,Proxies\n - DOMAIN-SUFFIX,blog.com,Proxies\n - DOMAIN-SUFFIX,blogcdn.com,Proxies\n - DOMAIN-SUFFIX,blogger.com,Proxies\n - DOMAIN-SUFFIX,bloglovin.com,Proxies\n - DOMAIN-SUFFIX,blogsmithmedia.com,Proxies\n - DOMAIN-SUFFIX,blogspot.hk,Proxies\n - DOMAIN-SUFFIX,bloomberg.cn,Proxies\n - DOMAIN-SUFFIX,bloomberg.com,Proxies\n - DOMAIN-SUFFIX,books.com.tw,Proxies\n - DOMAIN-SUFFIX,boomtrain.com,Proxies\n - DOMAIN-SUFFIX,botanwang.com,Proxies\n - DOMAIN-SUFFIX,box.com,Proxies\n - DOMAIN-SUFFIX,box.net,Proxies\n - DOMAIN-SUFFIX,boxun.com,Proxies\n - DOMAIN-SUFFIX,cachefly.net,Proxies\n - DOMAIN-SUFFIX,cbc.ca,Proxies\n - DOMAIN-SUFFIX,cdn.angruo.com,Proxies\n - DOMAIN-SUFFIX,cdn.segment.com,Proxies\n - DOMAIN-SUFFIX,cdnst.net,Proxies\n - DOMAIN-SUFFIX,celestrak.com,Proxies\n - DOMAIN-SUFFIX,census.gov,Proxies\n - DOMAIN-SUFFIX,certificate-transparency.org,Proxies\n - DOMAIN-SUFFIX,chinadigitaltimes.net,Proxies\n - DOMAIN-SUFFIX,chinatimes.com,Proxies\n - DOMAIN-SUFFIX,chrome.com,Proxies\n - DOMAIN-SUFFIX,chromecast.com,Proxies\n - DOMAIN-SUFFIX,chromercise.com,Proxies\n - DOMAIN-SUFFIX,chromestatus.com,Proxies\n - DOMAIN-SUFFIX,chromium.org,Proxies\n - DOMAIN-SUFFIX,cl.ly,Proxies\n - DOMAIN-SUFFIX,clien.net,Proxies\n - DOMAIN-SUFFIX,cloud.cupronickel.goog,Proxies\n - DOMAIN-SUFFIX,cloudflare.com,Proxies\n - DOMAIN-SUFFIX,cloudfront.net,Proxies\n - DOMAIN-SUFFIX,cloudgarage.jp,Proxies\n - DOMAIN-SUFFIX,cloudmagic.com,Proxies\n - DOMAIN-SUFFIX,cmail19.com,Proxies\n - DOMAIN-SUFFIX,cnet.com,Proxies\n - DOMAIN-SUFFIX,cnn.com,Proxies\n - DOMAIN-SUFFIX,cocoapods.org,Proxies\n - DOMAIN-SUFFIX,comodoca.com,Proxies\n - DOMAIN-SUFFIX,crisp.chat,Proxies\n - DOMAIN-SUFFIX,culturedcode.com,Proxies\n - DOMAIN-SUFFIX,cygames.jp,Proxies\n - DOMAIN-SUFFIX,d.pr,Proxies\n - DOMAIN-SUFFIX,danilo.to,Proxies\n - DOMAIN-SUFFIX,daolan.net,Proxies\n - DOMAIN-SUFFIX,data-vocabulary.org,Proxies\n - DOMAIN-SUFFIX,dayone.me,Proxies\n - DOMAIN-SUFFIX,db.tt,Proxies\n - DOMAIN-SUFFIX,dcmilitary.com,Proxies\n - DOMAIN-SUFFIX,deja.com,Proxies\n - DOMAIN-SUFFIX,demdex.net,Proxies\n - DOMAIN-SUFFIX,deskconnect.com,Proxies\n - DOMAIN-SUFFIX,digisfera.com,Proxies\n - DOMAIN-SUFFIX,digitaltrends.com,Proxies\n - DOMAIN-SUFFIX,disconnect.me,Proxies\n - DOMAIN-SUFFIX,disq.us,Proxies\n - DOMAIN-SUFFIX,disqus.com,Proxies\n - DOMAIN-SUFFIX,disquscdn.com,Proxies\n - DOMAIN-SUFFIX,dler.io,Proxies\n - DOMAIN-SUFFIX,dnsimple.com,Proxies\n - DOMAIN-SUFFIX,docker.com,Proxies\n - DOMAIN-SUFFIX,doub.io,Proxies\n - DOMAIN-SUFFIX,dowjones.com,Proxies\n - DOMAIN-SUFFIX,dribbble.com,Proxies\n - DOMAIN-SUFFIX,droplr.com,Proxies\n - DOMAIN-SUFFIX,duckduckgo.com,Proxies\n - DOMAIN-SUFFIX,dueapp.com,Proxies\n - DOMAIN-SUFFIX,dw.com,Proxies\n - DOMAIN-SUFFIX,easybib.com,Proxies\n - DOMAIN-SUFFIX,economist.com,Proxies\n - DOMAIN-SUFFIX,edgecastcdn.net,Proxies\n - DOMAIN-SUFFIX,edgekey.net,Proxies\n - DOMAIN-SUFFIX,edgesuite.net,Proxies\n - DOMAIN-SUFFIX,engadget.com,Proxies\n - DOMAIN-SUFFIX,entrust.net,Proxies\n - DOMAIN-SUFFIX,eurekavpt.com,Proxies\n - DOMAIN-SUFFIX,evernote.com,Proxies\n - DOMAIN-SUFFIX,extmatrix.com,Proxies\n - DOMAIN-SUFFIX,eyny.com,Proxies\n - DOMAIN-SUFFIX,fabric.io,Proxies\n - DOMAIN-SUFFIX,fastly.net,Proxies\n - DOMAIN-SUFFIX,fastmail.com,Proxies\n - DOMAIN-SUFFIX,fc2.com,Proxies\n - DOMAIN-SUFFIX,feedburner.com,Proxies\n - DOMAIN-SUFFIX,feedly.com,Proxies\n - DOMAIN-SUFFIX,feedsportal.com,Proxies\n - DOMAIN-SUFFIX,firefox.com,Proxies\n - DOMAIN-SUFFIX,fiftythree.com,Proxies\n - DOMAIN-SUFFIX,firebaseio.com,Proxies\n - DOMAIN-SUFFIX,flexibits.com,Proxies\n - DOMAIN-SUFFIX,flickr.com,Proxies\n - DOMAIN-SUFFIX,flipboard.com,Proxies\n - DOMAIN-SUFFIX,flipkart.com,Proxies\n - DOMAIN-SUFFIX,flitto.com,Proxies\n - DOMAIN-SUFFIX,flurry.com,Proxies\n - DOMAIN-SUFFIX,freeopenProxy.com,Proxies\n - DOMAIN-SUFFIX,fubo.tv,Proxies\n - DOMAIN-SUFFIX,fullstory.com,Proxies\n - DOMAIN-SUFFIX,fzlm.net,Proxies\n - DOMAIN-SUFFIX,g.co,Proxies\n - DOMAIN-SUFFIX,gabia.net,Proxies\n - DOMAIN-SUFFIX,garena.com,Proxies\n - DOMAIN-SUFFIX,geni.us,Proxies\n - DOMAIN-SUFFIX,get.how,Proxies\n - DOMAIN-SUFFIX,getcloudapp.com,Proxies\n - DOMAIN-SUFFIX,getfoxyProxy.org,Proxies\n - DOMAIN-SUFFIX,getlantern.org,Proxies\n - DOMAIN-SUFFIX,getmdl.io,Proxies\n - DOMAIN-SUFFIX,getpricetag.com,Proxies\n - DOMAIN-SUFFIX,gfw.press,Proxies\n - DOMAIN-SUFFIX,ggpht.com,Proxies\n - DOMAIN-SUFFIX,ghostnoteapp.com,Proxies\n - DOMAIN-SUFFIX,ghcr.io,Proxies\n - DOMAIN-SUFFIX,git.io,Proxies\n - DOMAIN-SUFFIX,gitbook.com,Proxies\n - DOMAIN-SUFFIX,gitlab.com,Proxies\n - DOMAIN-SUFFIX,gitlab.io,Proxies\n - DOMAIN-SUFFIX,globalsign.com,Proxies\n - DOMAIN-SUFFIX,gmocloud.com,Proxies\n - DOMAIN-SUFFIX,gmodules.com,Proxies\n - DOMAIN-SUFFIX,go.com,Proxies\n - DOMAIN-SUFFIX,go.jp,Proxies\n - DOMAIN-SUFFIX,godaddy.com,Proxies\n - DOMAIN-SUFFIX,golang.org,Proxies\n - DOMAIN-SUFFIX,gongm.in,Proxies\n - DOMAIN-SUFFIX,goo.gl,Proxies\n - DOMAIN-SUFFIX,goodreaders.com,Proxies\n - DOMAIN-SUFFIX,goodreads.com,Proxies\n - DOMAIN-SUFFIX,gravatar.com,Proxies\n - DOMAIN-SUFFIX,gstatic.cn,Proxies\n - DOMAIN-SUFFIX,gstatic.com,Proxies\n - DOMAIN-SUFFIX,gunsamerica.com,Proxies\n - DOMAIN-SUFFIX,gvt0.com,Proxies\n - DOMAIN-SUFFIX,gvt1.com,Proxies\n - DOMAIN-SUFFIX,helpshift.com,Proxies\n - DOMAIN-SUFFIX,hitun.io,Proxies\n - DOMAIN-SUFFIX,hockeyapp.net,Proxies\n - DOMAIN-SUFFIX,homedepot.com,Proxies\n - DOMAIN-SUFFIX,hootsuite.com,Proxies\n - DOMAIN-SUFFIX,howtoforge.com,Proxies\n - DOMAIN-SUFFIX,i-cable.com,Proxies\n - DOMAIN-SUFFIX,iam.soy,Proxies\n - DOMAIN-SUFFIX,icoco.com,Proxies\n - DOMAIN-SUFFIX,icons8.com,Proxies\n - DOMAIN-SUFFIX,ift.tt,Proxies\n - DOMAIN-SUFFIX,ifttt.com,Proxies\n - DOMAIN-SUFFIX,imageshack.us,Proxies\n - DOMAIN-SUFFIX,img.ly,Proxies\n - DOMAIN-SUFFIX,imgur.com,Proxies\n - DOMAIN-SUFFIX,imore.com,Proxies\n - DOMAIN-SUFFIX,imtoken.fans,Proxies\n - DOMAIN-SUFFIX,ingress.com,Proxies\n - DOMAIN-SUFFIX,inoreader.com,Proxies\n - DOMAIN-SUFFIX,insder.co,Proxies\n - DOMAIN-SUFFIX,instapaper.com,Proxies\n - DOMAIN-SUFFIX,instructables.com,Proxies\n - DOMAIN-SUFFIX,io.io,Proxies\n - DOMAIN-SUFFIX,ip.sb,Proxies\n - DOMAIN-SUFFIX,ipaddress.com,Proxies\n - DOMAIN-SUFFIX,ipn.li,Proxies\n - DOMAIN-SUFFIX,is.gd,Proxies\n - DOMAIN-SUFFIX,ishowsapp.com,Proxies\n - DOMAIN-SUFFIX,issuu.com,Proxies\n - DOMAIN-SUFFIX,itgonglun.com,Proxies\n - DOMAIN-SUFFIX,itun.es,Proxies\n - DOMAIN-SUFFIX,ixquick.com,Proxies\n - DOMAIN-SUFFIX,j.mp,Proxies\n - DOMAIN-SUFFIX,javbus.com,Proxies\n - DOMAIN-SUFFIX,js.revsci.net,Proxies\n - DOMAIN-SUFFIX,jshint.com,Proxies\n - DOMAIN-SUFFIX,jtvnw.net,Proxies\n - DOMAIN-SUFFIX,justgetflux.com,Proxies\n - DOMAIN-SUFFIX,kakao.co.kr,Proxies\n - DOMAIN-SUFFIX,kakao.com,Proxies\n - DOMAIN-SUFFIX,kakaocdn.net,Proxies\n - DOMAIN-SUFFIX,kat.cr,Proxies\n - DOMAIN-SUFFIX,kenengba.com,Proxies\n - DOMAIN-SUFFIX,kik.com,Proxies\n - DOMAIN-SUFFIX,klip.me,Proxies\n - DOMAIN-SUFFIX,leancloud.com,Proxies\n - DOMAIN-SUFFIX,leetcode.com,Proxies\n - DOMAIN-SUFFIX,libsyn.com,Proxies\n - DOMAIN-SUFFIX,licdn.com,Proxies\n - DOMAIN-SUFFIX,lightboxcdn.com,Proxies\n - DOMAIN-SUFFIX,like.com,Proxies\n - DOMAIN-SUFFIX,linkedin.com,Proxies\n - DOMAIN-SUFFIX,linode.com,Proxies\n - DOMAIN-SUFFIX,lithium.com,Proxies\n - DOMAIN-SUFFIX,littlehj.com,Proxies\n - DOMAIN-SUFFIX,livefilestore.com,Proxies\n - DOMAIN-SUFFIX,llnwd.net,Proxies\n - DOMAIN-SUFFIX,localnetwork.uop,Proxies\n - DOMAIN-SUFFIX,logmein.com,Proxies\n - DOMAIN-SUFFIX,macid.co,Proxies\n - DOMAIN-SUFFIX,macromedia.com,Proxies\n - DOMAIN-SUFFIX,macrumors.com,Proxies\n - DOMAIN-SUFFIX,mangaup.jp,Proxies\n - DOMAIN-SUFFIX,manhuaren.com,Proxies\n - DOMAIN-SUFFIX,marketwatch.com,Proxies\n - DOMAIN-SUFFIX,mashable.com,Proxies\n - DOMAIN-SUFFIX,mathjax.org,Proxies\n - DOMAIN-SUFFIX,maven.org,Proxies\n - DOMAIN-SUFFIX,medium.com,Proxies\n - DOMAIN-SUFFIX,mega.co.nz,Proxies\n - DOMAIN-SUFFIX,mega.nz,Proxies\n - DOMAIN-SUFFIX,megaupload.com,Proxies\n - DOMAIN-SUFFIX,mindnode.com,Proxies\n - DOMAIN-SUFFIX,mixin.one,Proxies\n - DOMAIN-SUFFIX,mlssoccer.com,Proxies\n - DOMAIN-SUFFIX,mobile01.com,Proxies\n - DOMAIN-SUFFIX,modmyi.com,Proxies\n - DOMAIN-SUFFIX,moves-export.com,Proxies\n - DOMAIN-SUFFIX,mp3buscador.com,Proxies\n - DOMAIN-SUFFIX,mycnnews.com,Proxies\n - DOMAIN-SUFFIX,myfontastic.com,Proxies\n - DOMAIN-SUFFIX,mypikpak.com,Proxies\n - DOMAIN-SUFFIX,name.com,Proxies\n - DOMAIN-SUFFIX,nasa.gov,Proxies\n - DOMAIN-SUFFIX,ndr.de,Proxies\n - DOMAIN-SUFFIX,netdna-cdn.com,Proxies\n - DOMAIN-SUFFIX,newipnow.com,Proxies\n - DOMAIN-SUFFIX,nextmedia.com,Proxies\n - DOMAIN-SUFFIX,nicovideo.jp,Proxies\n - DOMAIN-SUFFIX,nih.gov,Proxies\n - DOMAIN-SUFFIX,nimg.jp,Proxies\n - DOMAIN-SUFFIX,nintendo.com,Proxies\n - DOMAIN-SUFFIX,nintendo.net,Proxies\n - DOMAIN-SUFFIX,notion.so,Proxies\n - DOMAIN-SUFFIX,novafile.com,Proxies\n - DOMAIN-SUFFIX,nrk.no,Proxies\n - DOMAIN-SUFFIX,nsstatic.net,Proxies\n - DOMAIN-SUFFIX,nssurge.com,Proxies\n - DOMAIN-SUFFIX,nyt.com,Proxies\n - DOMAIN-SUFFIX,nytimes.com,Proxies\n - DOMAIN-SUFFIX,nytimg.com,Proxies\n - DOMAIN-SUFFIX,nytstyle.com,Proxies\n - DOMAIN-SUFFIX,okx.com,Proxies\n - DOMAIN-SUFFIX,omnigroup.com,Proxies\n - DOMAIN-SUFFIX,ooyala.com,Proxies\n - DOMAIN-SUFFIX,openvpn.net,Proxies\n - DOMAIN-SUFFIX,openwrt.org,Proxies\n - DOMAIN-SUFFIX,orkut.com,Proxies\n - DOMAIN-SUFFIX,osha.gov,Proxies\n - DOMAIN-SUFFIX,osxdaily.com,Proxies\n - DOMAIN-SUFFIX,overcast.fm,Proxies\n - DOMAIN-SUFFIX,ow.ly,Proxies\n - DOMAIN-SUFFIX,paddle.com,Proxies\n - DOMAIN-SUFFIX,paddleapi.com,Proxies\n - DOMAIN-SUFFIX,panoramio.com,Proxies\n - DOMAIN-SUFFIX,parallels.com,Proxies\n - DOMAIN-SUFFIX,parse.com,Proxies\n - DOMAIN-SUFFIX,pdfexpert.com,Proxies\n - DOMAIN-SUFFIX,periscope.tv,Proxies\n - DOMAIN-SUFFIX,piaotian.net,Proxies\n - DOMAIN-SUFFIX,picacomic.com,Proxies\n - DOMAIN-SUFFIX,picasaweb.com,Proxies\n - DOMAIN-SUFFIX,pinboard.in,Proxies\n - DOMAIN-SUFFIX,ping.pe,Proxies\n - DOMAIN-SUFFIX,pinterest.com,Proxies\n - DOMAIN-SUFFIX,pixelmator.com,Proxies\n - DOMAIN-SUFFIX,pixiv.net,Proxies\n - DOMAIN-SUFFIX,pixnet.net,Proxies\n - DOMAIN-SUFFIX,playpcesor.com,Proxies\n - DOMAIN-SUFFIX,pokemon.com,Proxies\n - DOMAIN-SUFFIX,polymer-project.org,Proxies\n - DOMAIN-SUFFIX,popo.tw,Proxies\n - DOMAIN-SUFFIX,potato.im,Proxies\n - DOMAIN-SUFFIX,redd.it,Proxies\n - DOMAIN-SUFFIX,rthk.hk,Proxies\n - DOMAIN-SUFFIX,prfct.co,Proxies\n - DOMAIN-SUFFIX,proxfree.com,Proxies\n - DOMAIN-SUFFIX,psiphon3.com,Proxies\n - DOMAIN-SUFFIX,ptt.cc,Proxies\n - DOMAIN-SUFFIX,pubu.com.tw,Proxies\n - DOMAIN-SUFFIX,puffinbrowser.com,Proxies\n - DOMAIN-SUFFIX,pushbullet.com,Proxies\n - DOMAIN-SUFFIX,pushwoosh.com,Proxies\n - DOMAIN-SUFFIX,pximg.net,Proxies\n - DOMAIN-SUFFIX,quora.com,Proxies\n - DOMAIN-SUFFIX,quoracdn.net,Proxies\n - DOMAIN-SUFFIX,readingtimes.com.tw,Proxies\n - DOMAIN-SUFFIX,readmoo.com,Proxies\n - DOMAIN-SUFFIX,recaptcha.net,Proxies\n - DOMAIN-SUFFIX,reddit.com,Proxies\n - DOMAIN-SUFFIX,redditmedia.com,Proxies\n - DOMAIN-SUFFIX,redditstatic.com,Proxies\n - DOMAIN-SUFFIX,reuters.com,Proxies\n - DOMAIN-SUFFIX,rfi.fr,Proxies\n - DOMAIN-SUFFIX,rileyguide.com,Proxies\n - DOMAIN-SUFFIX,rime.im,Proxies\n - DOMAIN-SUFFIX,rsf.org,Proxies\n - DOMAIN-SUFFIX,sciencedaily.com,Proxies\n - DOMAIN-SUFFIX,sciencemag.org,Proxies\n - DOMAIN-SUFFIX,scribd.com,Proxies\n - DOMAIN-SUFFIX,search.com,Proxies\n - DOMAIN-SUFFIX,servebom.com,Proxies\n - DOMAIN-SUFFIX,sexinsex.net,Proxies\n - DOMAIN-SUFFIX,sfx.ms,Proxies\n - DOMAIN-SUFFIX,shadowsocks.org,Proxies\n - DOMAIN-SUFFIX,shadowverse.jp,Proxies\n - DOMAIN-SUFFIX,sharethis.com,Proxies\n - DOMAIN-SUFFIX,shazam.com,Proxies\n - DOMAIN-SUFFIX,shutterstock.com,Proxies\n - DOMAIN-SUFFIX,sidelinesnews.com,Proxies\n - DOMAIN-SUFFIX,simp.ly,Proxies\n - DOMAIN-SUFFIX,simplenote.com,Proxies\n - DOMAIN-SUFFIX,sketchappsources.com,Proxies\n - DOMAIN-SUFFIX,slack.com,Proxies\n - DOMAIN-SUFFIX,slack-edge.com,Proxies\n - DOMAIN-SUFFIX,slack-msgs.com,Proxies\n - DOMAIN-SUFFIX,slideshare.net,Proxies\n - DOMAIN-SUFFIX,smartdnsproxy.com,Proxies\n - DOMAIN-SUFFIX,smh.com.au,Proxies\n - DOMAIN-SUFFIX,snapchat.com,Proxies\n - DOMAIN-SUFFIX,sndcdn.com,Proxies\n - DOMAIN-SUFFIX,sockslist.net,Proxies\n - DOMAIN-SUFFIX,soundcloud.com,Proxies\n - DOMAIN-SUFFIX,sourceforge.net,Proxies\n - DOMAIN-SUFFIX,sowers.org.hk,Proxies\n - DOMAIN-SUFFIX,speedsmart.net,Proxies\n - DOMAIN-SUFFIX,spike.com,Proxies\n - DOMAIN-SUFFIX,squarespace.com,Proxies\n - DOMAIN-SUFFIX,ssa.gov,Proxies\n - DOMAIN-SUFFIX,sstatic.net,Proxies\n - DOMAIN-SUFFIX,st.luluku.pw,Proxies\n - DOMAIN-SUFFIX,stackoverflow.com,Proxies\n - DOMAIN-SUFFIX,starp2p.com,Proxies\n - DOMAIN-SUFFIX,startpage.com,Proxies\n - DOMAIN-SUFFIX,state.gov,Proxies\n - DOMAIN-SUFFIX,staticflickr.com,Proxies\n - DOMAIN-SUFFIX,storify.com,Proxies\n - DOMAIN-SUFFIX,stumbleupon.com,Proxies\n - DOMAIN-SUFFIX,sugarsync.com,Proxies\n - DOMAIN-SUFFIX,supermariorun.com,Proxies\n - DOMAIN-SUFFIX,surfeasy.com.au,Proxies\n - DOMAIN-SUFFIX,surge.run,Proxies\n - DOMAIN-SUFFIX,surrenderat20.net,Proxies\n - DOMAIN-SUFFIX,sydneytoday.com,Proxies\n - DOMAIN-SUFFIX,symauth.com,Proxies\n - DOMAIN-SUFFIX,symcb.com,Proxies\n - DOMAIN-SUFFIX,symcd.com,Proxies\n - DOMAIN-SUFFIX,t66y.com,Proxies\n - DOMAIN-SUFFIX,tablesgenerator.com,Proxies\n - DOMAIN-SUFFIX,tabtter.jp,Proxies\n - DOMAIN-SUFFIX,talk853.com,Proxies\n - DOMAIN-SUFFIX,talkboxapp.com,Proxies\n - DOMAIN-SUFFIX,talkonly.net,Proxies\n - DOMAIN-SUFFIX,tapbots.com,Proxies\n - DOMAIN-SUFFIX,tapbots.net,Proxies\n - DOMAIN-SUFFIX,teamviewer.com,Proxies\n - DOMAIN-SUFFIX,techcrunch.com,Proxies\n - DOMAIN-SUFFIX,technorati.com,Proxies\n - DOMAIN-SUFFIX,techsmith.com,Proxies\n - DOMAIN-SUFFIX,teddysun.com,Proxies\n - DOMAIN-SUFFIX,textnow.me,Proxies\n - DOMAIN-SUFFIX,thebobs.com,Proxies\n - DOMAIN-SUFFIX,theinitium.com,Proxies\n - DOMAIN-SUFFIX,thepiratebay.org,Proxies\n - DOMAIN-SUFFIX,theverge.com,Proxies\n - DOMAIN-SUFFIX,thewgo.org,Proxies\n - DOMAIN-SUFFIX,tiltbrush.com,Proxies\n - DOMAIN-SUFFIX,time.com,Proxies\n - DOMAIN-SUFFIX,timeinc.net,Proxies\n - DOMAIN-SUFFIX,tinder.com,Proxies\n - DOMAIN-SUFFIX,tiny.cc,Proxies\n - DOMAIN-SUFFIX,tinychat.com,Proxies\n - DOMAIN-SUFFIX,tinypic.com,Proxies\n - DOMAIN-SUFFIX,tmblr.co,Proxies\n - DOMAIN-SUFFIX,todoist.com,Proxies\n - DOMAIN-SUFFIX,togetter.com,Proxies\n - DOMAIN-SUFFIX,tokyocn.com,Proxies\n - DOMAIN-SUFFIX,tomshardware.com,Proxies\n - DOMAIN-SUFFIX,torcn.com,Proxies\n - DOMAIN-SUFFIX,torrentmac.net,Proxies\n - DOMAIN-SUFFIX,torrentprivacy.com,Proxies\n - DOMAIN-SUFFIX,torrentproject.se,Proxies\n - DOMAIN-SUFFIX,torrentz.eu,Proxies\n - DOMAIN-SUFFIX,tradingview.com,Proxies\n - DOMAIN-SUFFIX,traffichaus.com,Proxies\n - DOMAIN-SUFFIX,trakt.tv,Proxies\n - DOMAIN-SUFFIX,transparency.org,Proxies\n - DOMAIN-SUFFIX,trello.com,Proxies\n - DOMAIN-SUFFIX,trendsmap.com,Proxies\n - DOMAIN-SUFFIX,trulyergonomic.com,Proxies\n - DOMAIN-SUFFIX,trustasiassl.com,Proxies\n - DOMAIN-SUFFIX,tt-rss.org,Proxies\n - DOMAIN-SUFFIX,ttvnw.net,Proxies\n - DOMAIN-SUFFIX,tumblr.co,Proxies\n - DOMAIN-SUFFIX,tumblr.com,Proxies\n - DOMAIN-SUFFIX,turbobit.net,Proxies\n - DOMAIN-SUFFIX,tv.com,Proxies\n - DOMAIN-SUFFIX,tweetdeck.com,Proxies\n - DOMAIN-SUFFIX,tweetmarker.net,Proxies\n - DOMAIN-SUFFIX,twimg.co,Proxies\n - DOMAIN-SUFFIX,twitch.tv,Proxies\n - DOMAIN-SUFFIX,twitthat.com,Proxies\n - DOMAIN-SUFFIX,twtkr.com,Proxies\n - DOMAIN-SUFFIX,twttr.com,Proxies\n - DOMAIN-SUFFIX,txmblr.com,Proxies\n - DOMAIN-SUFFIX,typcn.com,Proxies\n - DOMAIN-SUFFIX,typekit.net,Proxies\n - DOMAIN-SUFFIX,typography.com,Proxies\n - DOMAIN-SUFFIX,ubertags.com,Proxies\n - DOMAIN-SUFFIX,ublock.org,Proxies\n - DOMAIN-SUFFIX,ubnt.com,Proxies\n - DOMAIN-SUFFIX,uchicago.edu,Proxies\n - DOMAIN-SUFFIX,udn.com,Proxies\n - DOMAIN-SUFFIX,ugo.com,Proxies\n - DOMAIN-SUFFIX,uhdwallpapers.org,Proxies\n - DOMAIN-SUFFIX,ulyssesapp.com,Proxies\n - DOMAIN-SUFFIX,unblockdmm.com,Proxies\n - DOMAIN-SUFFIX,unblocksites.co,Proxies\n - DOMAIN-SUFFIX,unpo.org,Proxies\n - DOMAIN-SUFFIX,unsplash.com,Proxies\n - DOMAIN-SUFFIX,untraceable.us,Proxies\n - DOMAIN-SUFFIX,uploaded.net,Proxies\n - DOMAIN-SUFFIX,uProxy.org,Proxies\n - DOMAIN-SUFFIX,upwork.com,Proxies\n - DOMAIN-SUFFIX,urchin.com,Proxies\n - DOMAIN-SUFFIX,urlparser.com,Proxies\n - DOMAIN-SUFFIX,us.to,Proxies\n - DOMAIN-SUFFIX,usertrust.com,Proxies\n - DOMAIN-SUFFIX,usgs.gov,Proxies\n - DOMAIN-SUFFIX,usma.edu,Proxies\n - DOMAIN-SUFFIX,uspto.gov,Proxies\n - DOMAIN-SUFFIX,ustream.tv,Proxies\n - DOMAIN-SUFFIX,v.gd,Proxies\n - DOMAIN-SUFFIX,v2ex.co,Proxies\n - DOMAIN-SUFFIX,v2ray.com,Proxies\n - DOMAIN-SUFFIX,van001.com,Proxies\n - DOMAIN-SUFFIX,vanpeople.com,Proxies\n - DOMAIN-SUFFIX,vansky.com,Proxies\n - DOMAIN-SUFFIX,vbstatic.co,Proxies\n - DOMAIN-SUFFIX,venchina.com,Proxies\n - DOMAIN-SUFFIX,venturebeat.com,Proxies\n - DOMAIN-SUFFIX,veoh.com,Proxies\n - DOMAIN-SUFFIX,verizonwireless.com,Proxies\n - DOMAIN-SUFFIX,viber.com,Proxies\n - DOMAIN-SUFFIX,vid.me,Proxies\n - DOMAIN-SUFFIX,videomega.tv,Proxies\n - DOMAIN-SUFFIX,vidinfo.org,Proxies\n - DOMAIN-SUFFIX,vimeo.com,Proxies\n - DOMAIN-SUFFIX,vimeocdn.com,Proxies\n - DOMAIN-SUFFIX,vimperator.org,Proxies\n - DOMAIN-SUFFIX,vine.co,Proxies\n - DOMAIN-SUFFIX,visibletweets.com,Proxies\n - DOMAIN-SUFFIX,viu.com,Proxies\n - DOMAIN-SUFFIX,vivaldi.com,Proxies\n - DOMAIN-SUFFIX,voachinese.com,Proxies\n - DOMAIN-SUFFIX,vocativ.com,Proxies\n - DOMAIN-SUFFIX,vox-cdn.com,Proxies\n - DOMAIN-SUFFIX,vpnaccount.org,Proxies\n - DOMAIN-SUFFIX,vpnbook.com,Proxies\n - DOMAIN-SUFFIX,vpngate.net,Proxies\n - DOMAIN-SUFFIX,vsco.co,Proxies\n - DOMAIN-SUFFIX,vultr.com,Proxies\n - DOMAIN-SUFFIX,vzw.com,Proxies\n - DOMAIN-SUFFIX,w.org,Proxies\n - DOMAIN-SUFFIX,w3schools.com,Proxies\n - DOMAIN-SUFFIX,wattpad.com,Proxies\n - DOMAIN-SUFFIX,web2project.net,Proxies\n - DOMAIN-SUFFIX,webfreer.com,Proxies\n - DOMAIN-SUFFIX,weblagu.com,Proxies\n - DOMAIN-SUFFIX,websnapr.com,Proxies\n - DOMAIN-SUFFIX,webtype.com,Proxies\n - DOMAIN-SUFFIX,webwarper.net,Proxies\n - DOMAIN-SUFFIX,wenxuecity.com,Proxies\n - DOMAIN-SUFFIX,westca.com,Proxies\n - DOMAIN-SUFFIX,westpoint.edu,Proxies\n - DOMAIN-SUFFIX,whatbrowser.org,Proxies\n - DOMAIN-SUFFIX,wikiwand.com,Proxies\n - DOMAIN-SUFFIX,wikileaks.info,Proxies\n - DOMAIN-SUFFIX,wikileaks.org,Proxies\n - DOMAIN-SUFFIX,wikileaks-forum.com,Proxies\n - DOMAIN-SUFFIX,wikimedia.org,Proxies\n - DOMAIN-SUFFIX,wikipedia.com,Proxies\n - DOMAIN-SUFFIX,wikipedia.org,Proxies\n - DOMAIN-SUFFIX,wn.com,Proxies\n - DOMAIN-SUFFIX,wordpress.com,Proxies\n - DOMAIN-SUFFIX,workflow.is,Proxies\n - DOMAIN-SUFFIX,workflowy.com,Proxies\n - DOMAIN-SUFFIX,worldcat.org,Proxies\n - DOMAIN-SUFFIX,wow.com,Proxies\n - DOMAIN-SUFFIX,wp.com,Proxies\n - DOMAIN-SUFFIX,wsj.com,Proxies\n - DOMAIN-SUFFIX,wsj.net,Proxies\n - DOMAIN-SUFFIX,wwitv.com,Proxies\n - DOMAIN-SUFFIX,x.com,Proxies\n - DOMAIN-SUFFIX,xanga.com,Proxies\n - DOMAIN-SUFFIX,xclient.info,Proxies\n - DOMAIN-SUFFIX,xda-developers.com,Proxies\n - DOMAIN-SUFFIX,xeeno.com,Proxies\n - DOMAIN-SUFFIX,xiti.com,Proxies\n - DOMAIN-SUFFIX,xn--ngstr-lra8j.com,Proxies\n - DOMAIN-SUFFIX,xteko.com,Proxies\n - DOMAIN-SUFFIX,xuite.net,Proxies\n - DOMAIN-SUFFIX,xvideos.com,Proxies\n - DOMAIN-SUFFIX,yahoo.com,Proxies\n - DOMAIN-SUFFIX,yahooapis.com,Proxies\n - DOMAIN-SUFFIX,yandex.com,Proxies\n - DOMAIN-SUFFIX,yasni.co.uk,Proxies\n - DOMAIN-SUFFIX,yastatic.net,Proxies\n - DOMAIN-SUFFIX,ycombinator.com,Proxies\n - DOMAIN-SUFFIX,yeeyi.com,Proxies\n - DOMAIN-SUFFIX,yesasia.com,Proxies\n - DOMAIN-SUFFIX,yes-news.com,Proxies\n - DOMAIN-SUFFIX,yidio.com,Proxies\n - DOMAIN-SUFFIX,yimg.com,Proxies\n - DOMAIN-SUFFIX,ying.com,Proxies\n - DOMAIN-SUFFIX,yorkbbs.ca,Proxies\n - DOMAIN-SUFFIX,youmaker.com,Proxies\n - DOMAIN-SUFFIX,yourlisten.com,Proxies\n - DOMAIN-SUFFIX,yoyo.org,Proxies\n - DOMAIN-SUFFIX,zacebook.com,Proxies\n - DOMAIN-SUFFIX,zalmos.com,Proxies\n - DOMAIN-SUFFIX,zaobao.com.sg,Proxies\n - DOMAIN-SUFFIX,zeutch.com,Proxies\n - DOMAIN-SUFFIX,zynamics.com,Proxies\n - DOMAIN-KEYWORD,appledaily,Proxies\n - DOMAIN-KEYWORD,beetalk,Proxies\n - DOMAIN-KEYWORD,blogspot,Proxies\n - DOMAIN-KEYWORD,dropbox,Proxies\n - DOMAIN-KEYWORD,facebook,Proxies\n - DOMAIN-KEYWORD,github,Proxies\n - DOMAIN-KEYWORD,instagram,Proxies\n - DOMAIN-KEYWORD,twitter,Proxies\n - DOMAIN-KEYWORD,whatsapp,Proxies\n - DOMAIN-KEYWORD,google,Proxies\n - DOMAIN-SUFFIX,1e100.net,Proxies\n - DOMAIN-SUFFIX,2mdn.net,Proxies\n - DOMAIN-SUFFIX,abc.xyz,Proxies\n - DOMAIN-SUFFIX,akamai.net,Proxies\n - DOMAIN-SUFFIX,appspot.com,Proxies\n - DOMAIN-SUFFIX,autodraw.com,Proxies\n - DOMAIN-SUFFIX,bandwagonhost.com,Proxies\n - DOMAIN-SUFFIX,blogblog.com,Proxies\n - DOMAIN-SUFFIX,chromeexperiments.com,Proxies\n - DOMAIN-SUFFIX,creativelab5.com,Proxies\n - DOMAIN-SUFFIX,crittercism.com,Proxies\n - DOMAIN-SUFFIX,culturalspot.org,Proxies\n - DOMAIN-SUFFIX,dartlang.org,Proxies\n - DOMAIN-SUFFIX,fb.com,Proxies\n - DOMAIN-SUFFIX,fb.me,Proxies\n - DOMAIN-SUFFIX,fbcdn.net,Proxies\n - DOMAIN-SUFFIX,fbsbx.com,Proxies\n - DOMAIN-SUFFIX,gcr.io,Proxies\n - DOMAIN-SUFFIX,gmail.com,Proxies\n - DOMAIN-SUFFIX,gosetsuden.jp,Proxies\n - DOMAIN-SUFFIX,gwtproject.org,Proxies\n - DOMAIN-SUFFIX,hackmd.io,Proxies\n - DOMAIN-SUFFIX,heroku.com,Proxies\n - DOMAIN-SUFFIX,html5rocks.com,Proxies\n - DOMAIN-SUFFIX,keyhole.com,Proxies\n - DOMAIN-SUFFIX,kobo.com,Proxies\n - DOMAIN-SUFFIX,kobobooks.com,Proxies\n - DOMAIN-SUFFIX,madewithcode.com,Proxies\n - DOMAIN-SUFFIX,material.io,Proxies\n - DOMAIN-SUFFIX,messenger.com,Proxies\n - DOMAIN-SUFFIX,netmarble.com,Proxies\n - DOMAIN-SUFFIX,nianticlabs.com,Proxies\n - DOMAIN-SUFFIX,pinimg.com,Proxies\n - DOMAIN-SUFFIX,proton.me,Proxies\n - DOMAIN-SUFFIX,pubnub.com,Proxies\n - DOMAIN-SUFFIX,scdn.co,Proxies\n - DOMAIN-SUFFIX,t.co,Proxies\n - DOMAIN-SUFFIX,tenor.com,Proxies\n - DOMAIN-SUFFIX,tensorflow.org,Proxies\n - DOMAIN-SUFFIX,toggleable.com,Proxies\n - DOMAIN-SUFFIX,torproject.org,Proxies\n - DOMAIN-SUFFIX,twimg.com,Proxies\n - DOMAIN-SUFFIX,twitpic.com,Proxies\n - DOMAIN-SUFFIX,unfiltered.news,Proxies\n - DOMAIN-SUFFIX,waveprotocol.org,Proxies\n - DOMAIN-SUFFIX,webmproject.org,Proxies\n - DOMAIN-SUFFIX,webrtc.org,Proxies\n - DOMAIN-SUFFIX,v2ex.com,Proxies\n - DOMAIN-KEYWORD,dlercloud,Proxies\n - DOMAIN-SUFFIX,vikacg.com,Proxies\n - DOMAIN-SUFFIX,picjs.xyz,Proxies\n - DOMAIN-SUFFIX,wheel-size.cn,Proxies\n - DOMAIN-SUFFIX,chalungu.cn,Proxies\n - IP-CIDR,13.32.0.0/16,Proxies,no-resolve\n - IP-CIDR,13.33.0.0/16,Proxies,no-resolve\n - IP-CIDR,13.35.0.0/17,Proxies,no-resolve\n - IP-CIDR,18.184.0.0/15,Proxies,no-resolve\n - IP-CIDR,18.194.0.0/15,Proxies,no-resolve\n - IP-CIDR,18.208.0.0/13,Proxies,no-resolve\n - IP-CIDR,18.232.0.0/14,Proxies,no-resolve\n - IP-CIDR,52.200.0.0/13,Proxies,no-resolve\n - IP-CIDR,52.58.0.0/15,Proxies,no-resolve\n - IP-CIDR,52.74.0.0/16,Proxies,no-resolve\n - IP-CIDR,52.77.0.0/16,Proxies,no-resolve\n - IP-CIDR,52.84.0.0/15,Proxies,no-resolve\n - IP-CIDR,54.156.0.0/14,Proxies,no-resolve\n - IP-CIDR,54.226.0.0/15,Proxies,no-resolve\n - IP-CIDR,54.230.156.0/22,Proxies,no-resolve\n - IP-CIDR,54.93.0.0/16,Proxies,no-resolve\n - IP-CIDR,103.4.96.0/22,Proxies,no-resolve\n - IP-CIDR,129.134.0.0/17,Proxies,no-resolve\n - IP-CIDR,157.240.0.0/17,Proxies,no-resolve\n - IP-CIDR,173.252.64.0/19,Proxies,no-resolve\n - IP-CIDR,173.252.96.0/19,Proxies,no-resolve\n - IP-CIDR,179.60.192.0/22,Proxies,no-resolve\n - IP-CIDR,185.60.216.0/22,Proxies,no-resolve\n - IP-CIDR,204.15.20.0/22,Proxies,no-resolve\n - IP-CIDR,31.13.24.0/21,Proxies,no-resolve\n - IP-CIDR,31.13.64.0/18,Proxies,no-resolve\n - IP-CIDR,45.64.40.0/22,Proxies,no-resolve\n - IP-CIDR,66.220.144.0/20,Proxies,no-resolve\n - IP-CIDR,69.171.224.0/19,Proxies,no-resolve\n - IP-CIDR,69.63.176.0/20,Proxies,no-resolve\n - IP-CIDR,74.119.76.0/22,Proxies,no-resolve\n - IP-CIDR,173.194.0.0/16,Proxies,no-resolve\n - IP-CIDR,74.125.0.0/16,Proxies,no-resolve\n - IP-CIDR,1.201.0.0/24,Proxies,no-resolve\n - IP-CIDR,103.246.56.0/22,Proxies,no-resolve\n - IP-CIDR,103.27.148.0/22,Proxies,no-resolve\n - IP-CIDR,110.76.140.0/22,Proxies,no-resolve\n - IP-CIDR,113.61.104.0/22,Proxies,no-resolve\n - IP-CIDR,27.0.236.0/22,Proxies,no-resolve\n - IP-CIDR,103.2.28.0/22,Proxies,no-resolve\n - IP-CIDR,119.235.224.0/21,Proxies,no-resolve\n - IP-CIDR,119.235.232.0/23,Proxies,no-resolve\n - IP-CIDR,119.235.235.0/24,Proxies,no-resolve\n - IP-CIDR,119.235.236.0/23,Proxies,no-resolve\n - IP-CIDR,125.6.146.0/24,Proxies,no-resolve\n - IP-CIDR,125.6.149.0/24,Proxies,no-resolve\n - IP-CIDR,125.6.190.0/24,Proxies,no-resolve\n - IP-CIDR,125.209.208.0/20,Proxies,no-resolve\n - IP-CIDR,203.104.103.0/24,Proxies,no-resolve\n - IP-CIDR,203.104.128.0/20,Proxies,no-resolve\n - IP-CIDR,203.174.66.64/26,Proxies,no-resolve\n - IP-CIDR,203.174.77.0/24,Proxies,no-resolve\n - IP-CIDR,13.251.24.157/24,Proxies,no-resolve\n - IP-CIDR,13.251.41.203/24,Proxies,no-resolve\n - IP-CIDR,17.252.156.147/24,Proxies,no-resolve\n - IP-CIDR,17.252.157.26/24,Proxies,no-resolve\n - IP-CIDR,74.86.0.0/16,Proxies,no-resolve\n - IP-CIDR,75.126.0.0/16,Proxies,no-resolve\n - IP-CIDR,174.37.0.0/16,Proxies,no-resolve\n - IP-CIDR,208.43.0.0/16,Proxies,no-resolve\n - DOMAIN-SUFFIX,abchina.com,Domestic\n - DOMAIN-SUFFIX,abchina.com.cn,Domestic\n - DOMAIN-SUFFIX,boc.cn,Domestic\n - DOMAIN-SUFFIX,citicbank.com,Domestic\n - DOMAIN-SUFFIX,ecitic.com,Domestic\n - DOMAIN-SUFFIX,ecitic.net,Domestic\n - DOMAIN-SUFFIX,ccb.com,Domestic\n - DOMAIN-SUFFIX,ccb.com.cn,Domestic\n - DOMAIN-SUFFIX,cebbank.com,Domestic\n - DOMAIN-SUFFIX,cmbchina.com,Domestic\n - DOMAIN-SUFFIX,cmbimg.com,Domestic\n - DOMAIN-SUFFIX,cmbt.cn,Domestic\n - DOMAIN-SUFFIX,mbcloud.com,Domestic\n - DOMAIN-SUFFIX,icbc.com.cn,Domestic\n - DOMAIN-SUFFIX,pingan.com,Domestic\n - DOMAIN-SUFFIX,pingan.com.cn,Domestic\n - DOMAIN-KEYWORD,beplay,Domestic\n - DOMAIN,client.amplifi.com,Domestic\n - DOMAIN,ip.bjango.com,Domestic\n - DOMAIN-SUFFIX,alphassl.com,Domestic\n - DOMAIN-SUFFIX,edu.cn,Domestic\n - DOMAIN-SUFFIX,p4pfile.com,Domestic\n - DOMAIN-SUFFIX,zmzfile.com,Domestic\n - DOMAIN-SUFFIX,sony.com,Domestic\n - DOMAIN-SUFFIX,sonyentertainmentnetwork.com,Domestic\n - IP-CIDR,185.188.32.0/24,Domestic,no-resolve\n - IP-CIDR,185.188.33.0/24,Domestic,no-resolve\n - IP-CIDR,185.188.34.0/24,Domestic,no-resolve\n - IP-CIDR,185.188.35.0/24,Domestic,no-resolve\n - IP-CIDR6,2a0b:b580::/48,Domestic,no-resolve\n - IP-CIDR6,2a0b:b581::/48,Domestic,no-resolve\n - IP-CIDR6,2a0b:b582::/48,Domestic,no-resolve\n - IP-CIDR6,2a0b:b583::/48,Domestic,no-resolve\n - IP-CIDR,182.254.116.0/24,Domestic,no-resolve\n - DOMAIN-SUFFIX,10010.com,Domestic\n - DOMAIN-SUFFIX,10086.cn,Domestic\n - DOMAIN-SUFFIX,12306.cn,Domestic\n - DOMAIN-SUFFIX,12306.com,Domestic\n - DOMAIN-SUFFIX,126.net,Domestic\n - DOMAIN-SUFFIX,163.com,Domestic\n - DOMAIN-SUFFIX,189.cn,Domestic\n - DOMAIN-SUFFIX,360.cn,Domestic\n - DOMAIN-SUFFIX,360.com,Domestic\n - DOMAIN-SUFFIX,360buy.com,Domestic\n - DOMAIN-SUFFIX,360buyimg.com,Domestic\n - DOMAIN-SUFFIX,36kr.com,Domestic\n - DOMAIN-SUFFIX,51ym.me,Domestic\n - DOMAIN-SUFFIX,58.com,Domestic\n - DOMAIN-SUFFIX,8686c.com,Domestic\n - DOMAIN-SUFFIX,95516.com,Domestic\n - DOMAIN-SUFFIX,abercrombie.com,Domestic\n - DOMAIN-SUFFIX,acfun.tv,Domestic\n - DOMAIN-SUFFIX,adobesc.com,Domestic\n - DOMAIN-SUFFIX,aiaa.org,Domestic\n - DOMAIN-SUFFIX,air-matters.com,Domestic\n - DOMAIN-SUFFIX,air-matters.io,Domestic\n - DOMAIN-SUFFIX,aixifan.com,Domestic\n - DOMAIN-SUFFIX,alibaba.com,Domestic\n - DOMAIN-SUFFIX,alibabacloud.com,Domestic\n - DOMAIN-SUFFIX,alicdn.com,Domestic\n - DOMAIN-SUFFIX,alipay.com,Domestic\n - DOMAIN-SUFFIX,alipayobjects.com,Domestic\n - DOMAIN-SUFFIX,aliyun.com,Domestic\n - DOMAIN-SUFFIX,aliyuncs.com,Domestic\n - DOMAIN-SUFFIX,amap.com,Domestic\n - DOMAIN-SUFFIX,appshike.com,Domestic\n - DOMAIN-SUFFIX,appstore.com,Domestic\n - DOMAIN-SUFFIX,autonavi.com,Domestic\n - DOMAIN-SUFFIX,bababian.com,Domestic\n - DOMAIN-SUFFIX,baidu.com,Domestic\n - DOMAIN-SUFFIX,baidupcs.com,Domestic\n - DOMAIN-SUFFIX,bdimg.com,Domestic\n - DOMAIN-SUFFIX,bdstatic.com,Domestic\n - DOMAIN-SUFFIX,beatsbydre.com,Domestic\n - DOMAIN-SUFFIX,bochk.com,Domestic\n - DOMAIN-SUFFIX,caiyunapp.com,Domestic\n - DOMAIN-SUFFIX,ccgslb.com,Domestic\n - DOMAIN-SUFFIX,ccgslb.net,Domestic\n - DOMAIN-SUFFIX,chinacache.net,Domestic\n - DOMAIN-SUFFIX,chunbo.com,Domestic\n - DOMAIN-SUFFIX,chunboimg.com,Domestic\n - DOMAIN-SUFFIX,clouddn.com,Domestic\n - DOMAIN-SUFFIX,cloudsigma.com,Domestic\n - DOMAIN-SUFFIX,cloudxns.net,Domestic\n - DOMAIN-SUFFIX,cmct.tv,Domestic\n - DOMAIN-SUFFIX,cmfu.com,Domestic\n - DOMAIN-SUFFIX,chdbits.co,Domestic\n - DOMAIN-SUFFIX,cnlang.org,Domestic\n - DOMAIN-SUFFIX,coolapk.com,Domestic\n - DOMAIN-SUFFIX,cz88.net,Domestic\n - DOMAIN-SUFFIX,dct-cloud.com,Domestic\n - DOMAIN-SUFFIX,didialift.com,Domestic\n - DOMAIN-SUFFIX,digicert.com,Domestic\n - DOMAIN-SUFFIX,dler.cloud,Domestic\n - DOMAIN-SUFFIX,douban.com,Domestic\n - DOMAIN-SUFFIX,doubanio.com,Domestic\n - DOMAIN-SUFFIX,douyin.com,Domestic\n - DOMAIN-SUFFIX,douyu.com,Domestic\n - DOMAIN-SUFFIX,douyu.tv,Domestic\n - DOMAIN-SUFFIX,douyutv.com,Domestic\n - DOMAIN-SUFFIX,duokan.com,Domestic\n - DOMAIN-SUFFIX,duoshuo.com,Domestic\n - DOMAIN-SUFFIX,dytt8.net,Domestic\n - DOMAIN-SUFFIX,easou.com,Domestic\n - DOMAIN-SUFFIX,eudic.net,Domestic\n - DOMAIN-SUFFIX,ewqcxz.com,Domestic\n - DOMAIN-SUFFIX,feng.com,Domestic\n - DOMAIN-SUFFIX,fir.im,Domestic\n - DOMAIN-SUFFIX,frdic.com,Domestic\n - DOMAIN-SUFFIX,fresh-ideas.cc,Domestic\n - DOMAIN-SUFFIX,gameloft.com,Domestic\n - DOMAIN-SUFFIX,garmin.cn,Domestic\n - DOMAIN-SUFFIX,geetest.com,Domestic\n - DOMAIN-SUFFIX,godic.net,Domestic\n - DOMAIN-SUFFIX,goodread.com,Domestic\n - DOMAIN-SUFFIX,goofish.com,Domestic\n - DOMAIN-SUFFIX,gtimg.com,Domestic\n - DOMAIN-SUFFIX,haibian.com,Domestic\n - DOMAIN-SUFFIX,hao123.com,Domestic\n - DOMAIN-SUFFIX,haosou.com,Domestic\n - DOMAIN-SUFFIX,hdchina.org,Domestic\n - DOMAIN-SUFFIX,hdcmct.org,Domestic\n - DOMAIN-SUFFIX,hjfile.cn,Domestic\n - DOMAIN-SUFFIX,hkserversolution.com,Domestic\n - DOMAIN-SUFFIX,hollisterco.com,Domestic\n - DOMAIN-SUFFIX,hongxiu.com,Domestic\n - DOMAIN-SUFFIX,hujiang.com,Domestic\n - DOMAIN-SUFFIX,hxcdn.net,Domestic\n - DOMAIN-SUFFIX,icedropper.com,Domestic\n - DOMAIN-SUFFIX,iciba.com,Domestic\n - DOMAIN-SUFFIX,ifeng.com,Domestic\n - DOMAIN-SUFFIX,ifengimg.com,Domestic\n - DOMAIN-SUFFIX,images-amazon.com,Domestic\n - DOMAIN-SUFFIX,img4me.com,Domestic\n - DOMAIN-SUFFIX,ipapark.com,Domestic\n - DOMAIN-SUFFIX,ithome.com,Domestic\n - DOMAIN-SUFFIX,ixdzs.com,Domestic\n - DOMAIN-SUFFIX,jd.com,Domestic\n - DOMAIN-SUFFIX,jd.hk,Domestic\n - DOMAIN-SUFFIX,jianshu.com,Domestic\n - DOMAIN-SUFFIX,jianshu.io,Domestic\n - DOMAIN-SUFFIX,jianshuapi.com,Domestic\n - DOMAIN-SUFFIX,jiathis.com,Domestic\n - DOMAIN-SUFFIX,jomodns.com,Domestic\n - DOMAIN-SUFFIX,jsboxbbs.com,Domestic\n - DOMAIN-SUFFIX,knewone.com,Domestic\n - DOMAIN-SUFFIX,kuaidi100.com,Domestic\n - DOMAIN-SUFFIX,kugou.com,Domestic\n - DOMAIN-SUFFIX,lecloud.com,Domestic\n - DOMAIN-SUFFIX,lemicp.com,Domestic\n - DOMAIN-SUFFIX,letv.com,Domestic\n - DOMAIN-SUFFIX,letvcloud.com,Domestic\n - DOMAIN-SUFFIX,liyuans.com,Domestic\n - DOMAIN-SUFFIX,lizhi.io,Domestic\n - DOMAIN-SUFFIX,localizecdn.com,Domestic\n - DOMAIN-SUFFIX,lucifr.com,Domestic\n - DOMAIN-SUFFIX,luoo.net,Domestic\n - DOMAIN-SUFFIX,lxdns.com,Domestic\n - DOMAIN-SUFFIX,mai.tn,Domestic\n - DOMAIN-SUFFIX,meituan.com,Domestic\n - DOMAIN-SUFFIX,meizu.com,Domestic\n - DOMAIN-SUFFIX,metatrader4.com,Domestic\n - DOMAIN-SUFFIX,metatrader5.com,Domestic\n - DOMAIN-SUFFIX,mi.com,Domestic\n - DOMAIN-SUFFIX,miaopai.com,Domestic\n - DOMAIN-SUFFIX,miui.com,Domestic\n - DOMAIN-SUFFIX,miwifi.com,Domestic\n - DOMAIN-SUFFIX,mob.com,Domestic\n - DOMAIN-SUFFIX,moji.com,Domestic\n - DOMAIN-SUFFIX,moke.com,Domestic\n - DOMAIN-SUFFIX,mxhichina.com,Domestic\n - DOMAIN-SUFFIX,myqcloud.com,Domestic\n - DOMAIN-SUFFIX,myunlu.com,Domestic\n - DOMAIN-SUFFIX,ngabbs.com,Domestic\n - DOMAIN-SUFFIX,netease.com,Domestic\n - DOMAIN-SUFFIX,nfoservers.com,Domestic\n - DOMAIN-SUFFIX,nuomi.com,Domestic\n - DOMAIN-SUFFIX,ourbits.club,Domestic\n - DOMAIN-SUFFIX,ourdvs.com,Domestic\n - DOMAIN-SUFFIX,passthepopcorn.me,Domestic\n - DOMAIN-SUFFIX,pgyer.com,Domestic\n - DOMAIN-SUFFIX,pniao.com,Domestic\n - DOMAIN-SUFFIX,privatehd.to,Domestic\n - DOMAIN-SUFFIX,qbox.me,Domestic\n - DOMAIN-SUFFIX,qcloud.com,Domestic\n - DOMAIN-SUFFIX,qdaily.com,Domestic\n - DOMAIN-SUFFIX,qdmm.com,Domestic\n - DOMAIN-SUFFIX,qhimg.com,Domestic\n - DOMAIN-SUFFIX,qidian.com,Domestic\n - DOMAIN-SUFFIX,qihucdn.com,Domestic\n - DOMAIN-SUFFIX,qin.io,Domestic\n - DOMAIN-SUFFIX,qingmang.me,Domestic\n - DOMAIN-SUFFIX,qingmang.mobi,Domestic\n - DOMAIN-SUFFIX,qiniucdn.com,Domestic\n - DOMAIN-SUFFIX,qiniudn.com,Domestic\n - DOMAIN-SUFFIX,qq.com,Domestic\n - DOMAIN-SUFFIX,qqurl.com,Domestic\n - DOMAIN-SUFFIX,rarbg.to,Domestic\n - DOMAIN-SUFFIX,redacted.ch,Domestic\n - DOMAIN-SUFFIX,rrmj.tv,Domestic\n - DOMAIN-SUFFIX,ruguoapp.com,Domestic\n - DOMAIN-SUFFIX,sf-express.com,Domestic\n - DOMAIN-SUFFIX,sinaapp.com,Domestic\n - DOMAIN-SUFFIX,sinaimg.cn,Domestic\n - DOMAIN-SUFFIX,sinaimg.com,Domestic\n - DOMAIN-SUFFIX,smzdm.com,Domestic\n - DOMAIN-SUFFIX,snwx.com,Domestic\n - DOMAIN-SUFFIX,so.com,Domestic\n - DOMAIN-SUFFIX,sogou.com,Domestic\n - DOMAIN-SUFFIX,sogoucdn.com,Domestic\n - DOMAIN-SUFFIX,sohu.com,Domestic\n - DOMAIN-SUFFIX,soku.com,Domestic\n - DOMAIN-SUFFIX,soso.com,Domestic\n - DOMAIN-SUFFIX,sspai.com,Domestic\n - DOMAIN-SUFFIX,startssl.com,Domestic\n - DOMAIN-SUFFIX,suning.com,Domestic\n - DOMAIN-SUFFIX,symcd.com,Domestic\n - DOMAIN-SUFFIX,taobao.com,Domestic\n - DOMAIN-SUFFIX,tawk.link,Domestic\n - DOMAIN-SUFFIX,tawk.to,Domestic\n - DOMAIN-SUFFIX,tencent.com,Domestic\n - DOMAIN-SUFFIX,tencent-cloud.net,Domestic\n - DOMAIN-SUFFIX,tenpay.com,Domestic\n - DOMAIN-SUFFIX,tietuku.com,Domestic\n - DOMAIN-SUFFIX,tmall.com,Domestic\n - DOMAIN-SUFFIX,tmzvps.com,Domestic\n - DOMAIN-SUFFIX,trello.com,Domestic\n - DOMAIN-SUFFIX,trellocdn.com,Domestic\n - DOMAIN-SUFFIX,totheglory.im,Domestic\n - DOMAIN-SUFFIX,ttmeiju.com,Domestic\n - DOMAIN-SUFFIX,tudou.com,Domestic\n - DOMAIN-SUFFIX,udache.com,Domestic\n - DOMAIN-SUFFIX,umengcloud.com,Domestic\n - DOMAIN-SUFFIX,upaiyun.com,Domestic\n - DOMAIN-SUFFIX,upyun.com,Domestic\n - DOMAIN-SUFFIX,uxengine.net,Domestic\n - DOMAIN-SUFFIX,wandoujia.com,Domestic\n - DOMAIN-SUFFIX,weather.bjango.com,Domestic\n - DOMAIN-SUFFIX,webqxs.com,Domestic\n - DOMAIN-SUFFIX,wechat.com,Domestic\n - DOMAIN-SUFFIX,weibo.cn,Domestic\n - DOMAIN-SUFFIX,weibo.com,Domestic\n - DOMAIN-SUFFIX,weico.cc,Domestic\n - DOMAIN-SUFFIX,weiphone.com,Domestic\n - DOMAIN-SUFFIX,weiphone.net,Domestic\n - DOMAIN-SUFFIX,werewolf.53site.com,Domestic\n - DOMAIN-SUFFIX,wkcdn.com,Domestic\n - DOMAIN-SUFFIX,xdrig.com,Domestic\n - DOMAIN-SUFFIX,xhostfire.com,Domestic\n - DOMAIN-SUFFIX,xhscdn.com,Domestic\n - DOMAIN-SUFFIX,xiaohongshu.com,Domestic\n - DOMAIN-SUFFIX,xiaojukeji.com,Domestic\n - DOMAIN-SUFFIX,xiaomi.com,Domestic\n - DOMAIN-SUFFIX,xiaomi.net,Domestic\n - DOMAIN-SUFFIX,xiaomicp.com,Domestic\n - DOMAIN-SUFFIX,ximalaya.com,Domestic\n - DOMAIN-SUFFIX,xitek.com,Domestic\n - DOMAIN-SUFFIX,xmcdn.com,Domestic\n - DOMAIN-SUFFIX,xslb.net,Domestic\n - DOMAIN-SUFFIX,yach.me,Domestic\n - DOMAIN-SUFFIX,yeepay.com,Domestic\n - DOMAIN-SUFFIX,yhd.com,Domestic\n - DOMAIN-SUFFIX,yinxiang.com,Domestic\n - DOMAIN-SUFFIX,yixia.com,Domestic\n - DOMAIN-SUFFIX,ykimg.com,Domestic\n - DOMAIN-SUFFIX,youdao.com,Domestic\n - DOMAIN-SUFFIX,ysepay.cn,Domestic\n - DOMAIN-SUFFIX,ysepay.com,Domestic\n - DOMAIN-SUFFIX,yunjiasu-cdn.net,Domestic\n - DOMAIN-SUFFIX,zealer.com,Domestic\n - DOMAIN-SUFFIX,zgslb.net,Domestic\n - DOMAIN-SUFFIX,zhihu.com,Domestic\n - DOMAIN-SUFFIX,zhimg.com,Domestic\n - DOMAIN-SUFFIX,zimuzu.tv,Domestic\n - DOMAIN-SUFFIX,zmz002.com,Domestic\n - IP-CIDR,1.255.62.0/24,Domestic,no-resolve\n - DOMAIN-SUFFIX,gov.cn,Domestic\n - DOMAIN-SUFFIX,cn,Domestic\n - DOMAIN-KEYWORD,apple.com.akadns.net,Apple\n - DOMAIN-KEYWORD,icloud.com.akadns.net,Apple\n - DOMAIN-SUFFIX,aaplimg.com,Apple\n - DOMAIN-SUFFIX,apple.co,Apple\n - DOMAIN-SUFFIX,apple.com,Apple\n - DOMAIN-SUFFIX,apple-cloudkit.com,Apple\n - DOMAIN-SUFFIX,apple-mapkit.com,Apple\n - DOMAIN-SUFFIX,appsto.re,Apple\n - DOMAIN-SUFFIX,cdn-apple.com,Apple\n - DOMAIN-SUFFIX,icloud.com,Apple\n - DOMAIN-SUFFIX,icloud-content.com,Apple\n - DOMAIN-SUFFIX,itunes.com,Apple\n - DOMAIN-SUFFIX,me.com,Apple\n - DOMAIN-SUFFIX,mzstatic.com,Apple\n - IP-CIDR,17.0.0.0/8,Apple,no-resolve\n - IP-CIDR,63.92.224.0/19,Apple,no-resolve\n - IP-CIDR,65.199.22.0/23,Apple,no-resolve\n - IP-CIDR,139.178.128.0/18,Apple,no-resolve\n - IP-CIDR,144.178.0.0/19,Apple,no-resolve\n - IP-CIDR,144.178.36.0/22,Apple,no-resolve\n - IP-CIDR,144.178.48.0/20,Apple,no-resolve\n - IP-CIDR,192.35.50.0/24,Apple,no-resolve\n - IP-CIDR,198.183.17.0/24,Apple,no-resolve\n - IP-CIDR,205.180.175.0/24,Apple,no-resolve\n - DOMAIN-SUFFIX,apple.comscoreresearch.com,Apple\n - DOMAIN-SUFFIX,apple.news,Apple\n - PROCESS-NAME,com.apple.geod,Apple\n - DOMAIN-SUFFIX,bitcointalk.org,Crypto\n - DOMAIN-SUFFIX,aex.com,Crypto\n - DOMAIN-SUFFIX,bibox.com,Crypto\n - DOMAIN-SUFFIX,bitfinex.com,Crypto\n - DOMAIN-SUFFIX,bithumb.com,Crypto\n - DOMAIN-SUFFIX,bitmex.com,Crypto\n - DOMAIN-SUFFIX,bitstamp.net,Crypto\n - DOMAIN-SUFFIX,bittrex.com,Crypto\n - DOMAIN-SUFFIX,bybit.com,Crypto\n - DOMAIN-SUFFIX,coinbase.com,Crypto\n - DOMAIN-SUFFIX,coincheck.com,Crypto\n - DOMAIN-SUFFIX,coinone.co.kr,Crypto\n - DOMAIN-SUFFIX,gemini.com,Crypto\n - DOMAIN-SUFFIX,korbit.co.kr,Crypto\n - DOMAIN-SUFFIX,kraken.com,Crypto\n - DOMAIN-SUFFIX,kucoin.com,Crypto\n - DOMAIN-SUFFIX,liquid.com,Crypto\n - DOMAIN-SUFFIX,poloniex.com,Crypto\n - DOMAIN-SUFFIX,bitbank.cc,Crypto\n - DOMAIN-SUFFIX,bitcoin.org,Crypto\n - DOMAIN-SUFFIX,bitquick.co,Crypto\n - DOMAIN-SUFFIX,btcbox.co.jp,Crypto\n - DOMAIN-SUFFIX,cex.io,Crypto\n - DOMAIN-SUFFIX,dogecoin.com,Crypto\n - DOMAIN-SUFFIX,paxful.com,Crypto\n - DOMAIN-SUFFIX,tether.to,Crypto\n - DOMAIN-SUFFIX,dydx.exchange,Crypto\n - DOMAIN-SUFFIX,solana.com,Crypto\n - DOMAIN-SUFFIX,avax.network,Crypto\n - DOMAIN-SUFFIX,optimism.io,Crypto\n - DOMAIN-SUFFIX,arbitrum.io,Crypto\n - DOMAIN-SUFFIX,poly.network,Crypto\n - DOMAIN-SUFFIX,zkscan.io,Crypto\n - DOMAIN-SUFFIX,zksync.io,Crypto\n - DOMAIN-SUFFIX,boba.network,Crypto\n - DOMAIN-SUFFIX,binance.cc,Crypto\n - DOMAIN-SUFFIX,binance.cloud,Crypto\n - DOMAIN-SUFFIX,binance.com,Crypto\n - DOMAIN-SUFFIX,binance.im,Crypto\n - DOMAIN-SUFFIX,binance.me,Crypto\n - DOMAIN-SUFFIX,binance.us,Crypto\n - DOMAIN-SUFFIX,bnappzh.co,Crypto\n - DOMAIN-SUFFIX,bnappzh.com,Crypto\n - DOMAIN-SUFFIX,bnbstatic.com,Crypto\n - DOMAIN-SUFFIX,bntrace.com,Crypto\n - DOMAIN-SUFFIX,binance.charity,Crypto\n - DOMAIN-SUFFIX,binance.co,Crypto\n - DOMAIN-SUFFIX,binance.info,Crypto\n - DOMAIN-SUFFIX,binance.net,Crypto\n - DOMAIN-SUFFIX,binance.org,Crypto\n - DOMAIN-SUFFIX,binance.vision,Crypto\n - DOMAIN-SUFFIX,binanceapi.com,Crypto\n - DOMAIN-SUFFIX,binancezh.be,Crypto\n - DOMAIN-SUFFIX,binancezh.biz,Crypto\n - DOMAIN-SUFFIX,binancezh.cc,Crypto\n - DOMAIN-SUFFIX,binancezh.co,Crypto\n - DOMAIN-SUFFIX,binancezh.com,Crypto\n - DOMAIN-SUFFIX,binancezh.info,Crypto\n - DOMAIN-SUFFIX,binancezh.ink,Crypto\n - DOMAIN-SUFFIX,binancezh.kim,Crypto\n - DOMAIN-SUFFIX,binancezh.link,Crypto\n - DOMAIN-SUFFIX,binancezh.live,Crypto\n - DOMAIN-SUFFIX,binancezh.mobi,Crypto\n - DOMAIN-SUFFIX,binancezh.net,Crypto\n - DOMAIN-SUFFIX,binancezh.pro,Crypto\n - DOMAIN-SUFFIX,binancezh.sh,Crypto\n - DOMAIN-SUFFIX,binancezh.top,Crypto\n - DOMAIN-SUFFIX,bnappzh.mobi,Crypto\n - DOMAIN-SUFFIX,bsc.getblock.io,Crypto\n - DOMAIN-SUFFIX,bscscan.com,Crypto\n - PROCESS-NAME,Binance.exe,Crypto\n - DOMAIN-KEYWORD,binance,Crypto\n - DOMAIN-SUFFIX,hbabit.com,Crypto\n - DOMAIN-SUFFIX,hbfile.net,Crypto\n - DOMAIN-SUFFIX,huobi.com,Crypto\n - DOMAIN-SUFFIX,huobi.me,Crypto\n - DOMAIN-SUFFIX,huobi.pro,Crypto\n - DOMAIN-SUFFIX,huobi.sc,Crypto\n - DOMAIN-SUFFIX,huobiasia.vip,Crypto\n - DOMAIN-SUFFIX,huobigroup.com,Crypto\n - DOMAIN-SUFFIX,huobitoken.com,Crypto\n - DOMAIN-SUFFIX,heco-scan.com,Crypto\n - DOMAIN-SUFFIX,hecoview.com,Crypto\n - DOMAIN-SUFFIX,hbfile.net,Crypto\n - DOMAIN-SUFFIX,huobi.br.com,Crypto\n - DOMAIN-SUFFIX,bitderiv.com,Crypto\n - DOMAIN-SUFFIX,hecochain.com,Crypto\n - DOMAIN-SUFFIX,huobi.ws,Crypto\n - DOMAIN-SUFFIX,huobi.ug,Crypto\n - DOMAIN-SUFFIX,huobi.co.ma,Crypto\n - DOMAIN-SUFFIX,huobi.br.com,Crypto\n - PROCESS-NAME,Huobi.exe,Crypto\n - DOMAIN-KEYWORD,huobi,Crypto\n - DOMAIN-SUFFIX,okex.com,Crypto\n - DOMAIN-SUFFIX,okx.com,Crypto\n - PROCESS-NAME,OKX.exe,Crypto\n - DOMAIN-KEYWORD,okx,Crypto\n - DOMAIN-SUFFIX,asproex.com,Crypto\n - DOMAIN-SUFFIX,asproexapi.com,Crypto\n - DOMAIN-SUFFIX,bitflyer.com,Crypto\n - DOMAIN-SUFFIX,bitflyer.jp,Crypto\n - DOMAIN-SUFFIX,bisq.io,Crypto\n - DOMAIN-SUFFIX,bisq.network,Crypto\n - DOMAIN-SUFFIX,bitsquare.io,Crypto\n - DOMAIN-SUFFIX,coinone.co.kr,Crypto\n - DOMAIN-SUFFIX,coinonecore.com,Crypto\n - DOMAIN-SUFFIX,coinonecorp.com,Crypto\n - DOMAIN-SUFFIX,devcon.org,Crypto\n - DOMAIN-SUFFIX,ethereum.foundation,Crypto\n - DOMAIN-SUFFIX,ethereum.org,Crypto\n - DOMAIN-SUFFIX,etherscan.io,Crypto\n - DOMAIN-SUFFIX,nansen.ai,Crypto\n - DOMAIN-SUFFIX,ethgasstation.info,Crypto\n - DOMAIN-SUFFIX,watchtheburn.com,Crypto\n - DOMAIN-SUFFIX,flashbots.net,Crypto\n - DOMAIN-SUFFIX,cryptofees.info,Crypto\n - DOMAIN-SUFFIX,etherscan.io,Crypto\n - DOMAIN-SUFFIX,ethereum-magicians.org,Crypto\n - DOMAIN-SUFFIX,vitalik.ca,Crypto\n - DOMAIN-SUFFIX,ethfans.org,Crypto\n - DOMAIN-SUFFIX,ethereum.cn,Crypto\n - DOMAIN-SUFFIX,ethereum.stackexchange.com,Crypto\n - DOMAIN-SUFFIX,etherscan.com,Crypto\n - DOMAIN-SUFFIX,parity.io,Crypto\n - DOMAIN-SUFFIX,ethernodes.org,Crypto\n - DOMAIN-SUFFIX,localbitcoins.com,Crypto\n - DOMAIN-SUFFIX,localbitcoinschain.com,Crypto\n - DOMAIN-SUFFIX,zb.app,Crypto\n - DOMAIN-SUFFIX,zb.com,Crypto\n - DOMAIN-SUFFIX,zb.io,Crypto\n - DOMAIN-SUFFIX,zb.live,Crypto\n - DOMAIN-SUFFIX,aicoin.com,Crypto\n - DOMAIN-SUFFIX,aimoon.com,Crypto\n - DOMAIN-SUFFIX,coingecko.com,Crypto\n - DOMAIN-SUFFIX,coinmarketcap.com,Crypto\n - DOMAIN-SUFFIX,glassnode.com,Crypto\n - DOMAIN-SUFFIX,coinmetrics.io,Crypto\n - DOMAIN-SUFFIX,tokenview.com,Crypto\n - DOMAIN-SUFFIX,oklink.com,Crypto\n - DOMAIN-SUFFIX,blockchair.com,Crypto\n - DOMAIN-SUFFIX,intotheblock.com,Crypto\n - DOMAIN-SUFFIX,bytetree.com,Crypto\n - DOMAIN-SUFFIX,coin.dance,Crypto\n - DOMAIN-SUFFIX,defieye.io,Crypto\n - DOMAIN-SUFFIX,duneanalytics.com,Crypto\n - DOMAIN-SUFFIX,tokenterminal.com,Crypto\n - DOMAIN-SUFFIX,dapp.review,Crypto\n - DOMAIN-SUFFIX,dappradar.com,Crypto\n - DOMAIN-SUFFIX,stateofthedapps.com,Crypto\n - DOMAIN-SUFFIX,thegraph.com,Crypto\n - DOMAIN-SUFFIX,debank.com,Crypto\n - DOMAIN-SUFFIX,vfat.tools,Crypto\n - DOMAIN-SUFFIX,loanscan.io,Crypto\n - DOMAIN-SUFFIX,defirate.com,Crypto\n - DOMAIN-SUFFIX,defipulse.com,Crypto\n - DOMAIN-SUFFIX,apy999.com,Crypto\n - DOMAIN-SUFFIX,defieye.io,Crypto\n - DOMAIN-SUFFIX,dextools.io,Crypto\n - DOMAIN-SUFFIX,tradingview.com,Crypto\n - DOMAIN-SUFFIX,dcabtc.com,Crypto\n - DOMAIN-SUFFIX,chainalysis.com,Crypto\n - DOMAIN-SUFFIX,cryptoquant.com,Crypto\n - DOMAIN-SUFFIX,viewbase.com,Crypto\n - DOMAIN-SUFFIX,bitcoinity.org,Crypto\n - DOMAIN-SUFFIX,cryptocompare.com,Crypto\n - DOMAIN-SUFFIX,coincodex.com,Crypto\n - DOMAIN-SUFFIX,cointrendz.com,Crypto\n - DOMAIN-SUFFIX,coincheckup.com,Crypto\n - DOMAIN-SUFFIX,thetie.io,Crypto\n - DOMAIN-SUFFIX,cryptorank.io,Crypto\n - DOMAIN-SUFFIX,tradeblock.com,Crypto\n - DOMAIN-SUFFIX,nyctale.io,Crypto\n - DOMAIN-SUFFIX,dovemetrics.com,Crypto\n - DOMAIN-SUFFIX,cryptorank.io,Crypto\n - DOMAIN-SUFFIX,icodrops.com,Crypto\n - DOMAIN-SUFFIX,chainbroker.io,Crypto\n - DOMAIN-SUFFIX,crunchbase.com,Crypto\n - DOMAIN-SUFFIX,defillama.com,Crypto\n - DOMAIN-SUFFIX,coinowo.com,Crypto\n - DOMAIN-SUFFIX,earni.fi,Crypto\n - DOMAIN-SUFFIX,dropsearn.com,Crypto\n - DOMAIN-SUFFIX,bitcoin.it,Crypto\n - DOMAIN-SUFFIX,bitcoinmagazine.com,Crypto\n - DOMAIN-SUFFIX,blockchain.com,Crypto\n - DOMAIN-SUFFIX,tronscan.org,Crypto\n - DOMAIN-SUFFIX,btc.com,Crypto\n - DOMAIN-SUFFIX,f2pool.com,Crypto\n - DOMAIN-SUFFIX,cbeci.org,Crypto\n - DOMAIN-SUFFIX,digiconomist.net,Crypto\n - DOMAIN-SUFFIX,1ml.com,Crypto\n - DOMAIN-SUFFIX,bitcoinvisuals.com,Crypto\n - DOMAIN-SUFFIX,crypto51.app,Crypto\n - DOMAIN-SUFFIX,masternodes.online,Crypto\n - DOMAIN-SUFFIX,bitnodes.earn.com,Crypto\n - DOMAIN-SUFFIX,poolin.com,Crypto\n - DOMAIN-SUFFIX,ethermine.org,Crypto\n - DOMAIN-SUFFIX,ewapool.net,Crypto\n - DOMAIN-SUFFIX,ftx.com,Crypto\n - DOMAIN-KEYWORD,metamask,Crypto\n - DOMAIN,token-api.metaswap.codefi.network,Crypto\n - DOMAIN,min-api.cryptocompare.com,Crypto\n - DOMAIN-SUFFIX,opensea.io,Crypto\n - DOMAIN-SUFFIX,nftscan.com,Crypto\n - DOMAIN-SUFFIX,makersplace.com,Crypto\n - DOMAIN-SUFFIX,nonfungible.com,Crypto\n - DOMAIN-SUFFIX,cryptoslam.io,Crypto\n - DOMAIN-SUFFIX,cryptoart.io,Crypto\n - DOMAIN-SUFFIX,nftcalendar.io,Crypto\n - DOMAIN-SUFFIX,nftgo.io,Crypto\n - DOMAIN-SUFFIX,filecoin.io,Crypto\n - DOMAIN-SUFFIX,docs.lotu.sh,Crypto\n - DOMAIN-SUFFIX,ipfs.io,Crypto\n - DOMAIN-SUFFIX,docs.ipfs.io,Crypto\n - DOMAIN-SUFFIX,discuss.ipfs.io,Crypto\n - DOMAIN-SUFFIX,eos.io,Crypto\n - DOMAIN-SUFFIX,developers.eos.io,Crypto\n - DOMAIN-SUFFIX,block.one,Crypto\n - DOMAIN-SUFFIX,eostracker.io,Crypto\n - DOMAIN-SUFFIX,eosflare.io,Crypto\n - DOMAIN-SUFFIX,eospark.com,Crypto\n - DOMAIN-SUFFIX,bloks.io,Crypto\n - DOMAIN-SUFFIX,lightning.engineering,Crypto\n - DOMAIN-SUFFIX,lightning.community,Crypto\n - DOMAIN-SUFFIX,acinq.co,Crypto\n - DOMAIN-SUFFIX,1ml.com,Crypto\n - DOMAIN-SUFFIX,tokenpocket.pro,Crypto\n - DOMAIN-SUFFIX,token.im,Crypto\n - DOMAIN-SUFFIX,phantom.app,Crypto\n - DOMAIN-SUFFIX,tronlink.org,Crypto\n - DOMAIN-SUFFIX,myetherwallet.com,Crypto\n - DOMAIN-SUFFIX,jaxx.io,Crypto\n - DOMAIN-SUFFIX,trustwalletapp.com,Crypto\n - DOMAIN-SUFFIX,gate.ac,Crypto\n - DOMAIN-SUFFIX,gate.io,Crypto\n - DOMAIN-SUFFIX,mexc.com,Crypto\n - DOMAIN-SUFFIX,sushi.com,Crypto\n - DOMAIN-SUFFIX,uniswap.org,Crypto\n - DOMAIN-SUFFIX,sunswap.com,Crypto\n - DOMAIN-SUFFIX,traderjoexyz.com,Crypto\n - DOMAIN-SUFFIX,raydium.io,Crypto\n - DOMAIN-SUFFIX,synthetix.io,Crypto\n - DOMAIN-SUFFIX,aave.com,Crypto\n - DOMAIN-SUFFIX,compound.finance,Crypto\n - DOMAIN-SUFFIX,makerdao.com,Crypto\n - DOMAIN-SUFFIX,wbtc.network,Crypto\n - DOMAIN-SUFFIX,pancakeswap.finance,Crypto\n - DOMAIN-SUFFIX,pancakeswap.com,Crypto\n - DOMAIN-SUFFIX,mdex.co,Crypto\n - DOMAIN-SUFFIX,mdex.one,Crypto\n - DOMAIN-SUFFIX,mdex.com,Crypto\n - DOMAIN-SUFFIX,mdex.me,Crypto\n - DOMAIN-SUFFIX,1inch.io,Crypto\n - DOMAIN-SUFFIX,discord.com,Discord\n - DOMAIN-SUFFIX,discord.gg,Discord\n - DOMAIN-SUFFIX,discord.media,Discord\n - DOMAIN-SUFFIX,discordapp.com,Discord\n - DOMAIN-SUFFIX,discordapp.net,Discord\n - DOMAIN-SUFFIX,discordstatus.com,Discord\n - DOMAIN,mtalk.google.com,Google FCM\n - DOMAIN,mtalk4.google.com,Google FCM\n - DOMAIN,mtalk-staging.google.com,Google FCM\n - DOMAIN,mtalk-dev.google.com,Google FCM\n - DOMAIN,alt1-mtalk.google.com,Google FCM\n - DOMAIN,alt2-mtalk.google.com,Google FCM\n - DOMAIN,alt3-mtalk.google.com,Google FCM\n - DOMAIN,alt4-mtalk.google.com,Google FCM\n - DOMAIN,alt5-mtalk.google.com,Google FCM\n - DOMAIN,alt6-mtalk.google.com,Google FCM\n - DOMAIN,alt7-mtalk.google.com,Google FCM\n - DOMAIN,alt8-mtalk.google.com,Google FCM\n - DOMAIN,android.apis.google.com,Google FCM\n - DOMAIN,device-provisioning.googleapis.com,Google FCM\n - DOMAIN,firebaseinstallations.googleapis.com,Google FCM\n - IP-CIDR,64.233.177.188/32,Google FCM,no-resolve\n - IP-CIDR,64.233.186.188/32,Google FCM,no-resolve\n - IP-CIDR,64.233.187.188/32,Google FCM,no-resolve\n - IP-CIDR,64.233.188.188/32,Google FCM,no-resolve\n - IP-CIDR,64.233.189.188/32,Google FCM,no-resolve\n - IP-CIDR,74.125.23.188/32,Google FCM,no-resolve\n - IP-CIDR,74.125.24.188/32,Google FCM,no-resolve\n - IP-CIDR,74.125.28.188/32,Google FCM,no-resolve\n - IP-CIDR,74.125.127.188/32,Google FCM,no-resolve\n - IP-CIDR,74.125.137.188/32,Google FCM,no-resolve\n - IP-CIDR,74.125.203.188/32,Google FCM,no-resolve\n - IP-CIDR,74.125.204.188/32,Google FCM,no-resolve\n - IP-CIDR,74.125.206.188/32,Google FCM,no-resolve\n - IP-CIDR,108.177.125.188/32,Google FCM,no-resolve\n - IP-CIDR,142.250.4.188/32,Google FCM,no-resolve\n - IP-CIDR,142.250.10.188/32,Google FCM,no-resolve\n - IP-CIDR,142.250.31.188/32,Google FCM,no-resolve\n - IP-CIDR,142.250.96.188/32,Google FCM,no-resolve\n - IP-CIDR,172.217.194.188/32,Google FCM,no-resolve\n - IP-CIDR,172.217.218.188/32,Google FCM,no-resolve\n - IP-CIDR,172.217.219.188/32,Google FCM,no-resolve\n - IP-CIDR,172.253.63.188/32,Google FCM,no-resolve\n - IP-CIDR,172.253.122.188/32,Google FCM,no-resolve\n - IP-CIDR,173.194.175.188/32,Google FCM,no-resolve\n - IP-CIDR,173.194.218.188/32,Google FCM,no-resolve\n - IP-CIDR,209.85.233.188/32,Google FCM,no-resolve\n - DOMAIN-SUFFIX,augment.com,AI Suite\n - DOMAIN-SUFFIX,augmentcode.com,AI Suite\n - DOMAIN-SUFFIX,ai.com,AI Suite\n - DOMAIN-SUFFIX,chatgpt.com,AI Suite\n - DOMAIN-SUFFIX,openai.com,AI Suite\n - DOMAIN,chat.openai.com.cdn.cloudflare.net,AI Suite\n - DOMAIN,openaiapi-site.azureedge.net,AI Suite\n - DOMAIN,openaicom-api-bdcpf8c6d2e9atf6.z01.azurefd.net,AI Suite\n - DOMAIN,openaicomproductionae4b.blob.core.windows.net,AI Suite\n - DOMAIN,production-openaicom-storage.azureedge.net,AI Suite\n - DOMAIN-SUFFIX,cdn.oaistatic.com,AI Suite\n - DOMAIN-SUFFIX,oaiusercontent.com,AI Suite\n - DOMAIN,o33249.ingest.sentry.io,AI Suite\n - DOMAIN-SUFFIX,anthropic.com,AI Suite\n - DOMAIN-SUFFIX,claude.ai,AI Suite\n - DOMAIN-SUFFIX,claudeusercontent.com,AI Suite\n - DOMAIN,gateway.ai.cloudflare.com,AI Suite\n - DOMAIN-SUFFIX,diabrowser.engineering,AI Suite\n - DOMAIN-SUFFIX,windsurf.com,AI Suite\n - DOMAIN-SUFFIX,codeium.com,AI Suite\n - DOMAIN-SUFFIX,codeiumdata.com,AI Suite\n - DOMAIN-SUFFIX,chorus.sh,AI Suite\n - DOMAIN-SUFFIX,githubcopilot.com,AI Suite\n - DOMAIN-SUFFIX,microsoftonline.com,AI Suite\n - DOMAIN,copilot.microsoft.com,AI Suite\n - DOMAIN-SUFFIX,cursor.sh,AI Suite\n - DOMAIN-SUFFIX,dify.ai,AI Suite\n - DOMAIN,api.github.com,AI Suite\n - DOMAIN-SUFFIX,apis.google.com,AI Suite\n - DOMAIN-SUFFIX,bard.google.com,AI Suite\n - DOMAIN-SUFFIX,gemini.google.com,AI Suite\n - DOMAIN-SUFFIX,deepmind.com,AI Suite\n - DOMAIN-SUFFIX,deepmind.google,AI Suite\n - DOMAIN-SUFFIX,generativelanguage.googleapis.com,AI Suite\n - DOMAIN-SUFFIX,geller-pa.googleapis.com,AI Suite\n - DOMAIN-SUFFIX,proactivebackend-pa.googleapis.com,AI Suite\n - DOMAIN-KEYWORD,alkalimakersuite-pa.clients6.google.com,AI Suite\n - DOMAIN-SUFFIX,aistudio.google.com,AI Suite\n - DOMAIN-SUFFIX,makersuite.google.com,AI Suite\n - DOMAIN-SUFFIX,generativeai.google,AI Suite\n - DOMAIN,ai.google.dev,AI Suite\n - DOMAIN,alkalicore-pa.clients6.google.com,AI Suite\n - DOMAIN,waa-pa.clients6.google.com,AI Suite\n - DOMAIN-SUFFIX,notebooklm.google,AI Suite\n - DOMAIN-SUFFIX,notebooklm.google.com,AI Suite\n - DOMAIN-SUFFIX,x.ai,AI Suite\n - DOMAIN-SUFFIX,grok.com,AI Suite\n - DOMAIN-SUFFIX,groq.com,AI Suite\n - DOMAIN-SUFFIX,clipdrop.co,AI Suite\n - DOMAIN-SUFFIX,jasper.ai,AI Suite\n - DOMAIN-SUFFIX,meta.ai,AI Suite\n - DOMAIN-SUFFIX,openart.ai,AI Suite\n - DOMAIN-SUFFIX,openrouter.ai,AI Suite\n - DOMAIN-SUFFIX,perplexity.ai,AI Suite\n - DOMAIN-SUFFIX,poe.com,AI Suite\n - DOMAIN,apple-relay.apple.com,AI Suite\n - DOMAIN,apple-relay.cloudflare.com,AI Suite\n - DOMAIN,guzzoni.smoot.apple.com,AI Suite\n - DOMAIN-SUFFIX,sora.com,AI Suite\n - DOMAIN,sora-cdn.oaistatic.com,AI Suite\n - DOMAIN-SUFFIX,zed.dev,AI Suite\n - DOMAIN-SUFFIX,bh3.com,miHoYo\n - DOMAIN-SUFFIX,hoyolab.com,miHoYo\n - DOMAIN-SUFFIX,hoyoverse.com,miHoYo\n - DOMAIN-SUFFIX,mihayo.com,miHoYo\n - DOMAIN-SUFFIX,mihoyo.com,miHoYo\n - DOMAIN-SUFFIX,miyoushe.com,miHoYo\n - DOMAIN-SUFFIX,yuanshen.com,miHoYo\n - GEOIP,CN,Domestic\n - MATCH,Others', 'yaml', '{}', '2025-08-12 23:10:00.487', '2025-08-15 22:01:27.031'); -INSERT INTO `subscribe_application` (`id`, `name`, `icon`, `description`, `scheme`, `user_agent`, `is_default`, `subscribe_template`, `output_format`, `download_link`, `created_at`, `updated_at`) VALUES (4, 'SingBox', '', '', 'sing-box://import-remote-profile?url=${encodeURIComponent(url)}#${name}', 'sing-box', 0, '{{- /* ==== Partials ==== */ -}}\n{{- define \"AllNodeNames\" -}}\n{{- $first := true -}}\n{{- range .Proxies -}}\n {{- if $first -}}\n {{ .Name | quote }}\n {{- $first = false -}}\n {{- else -}}\n , {{ .Name | quote }}\n {{- end -}}\n{{- end -}}\n{{- end -}}\n\n{{- define \"WS\" -}}\n\"transport\": {\"type\": \"ws\", \"path\": {{ .Path | default \"/\" | quote }}{{- if .Host }}, \"headers\": {\"Host\": {{ .Host | quote }} }{{- end -}}}\n{{- end -}}\n\n{{- define \"GRPC\" -}}\n\"transport\": {\"type\": \"grpc\", \"service_name\": {{ .ServiceName | default \"grpc\" | quote }}}\n{{- end -}}\n\n{{- define \"TLS\" -}}\n\"tls\": {\"enabled\": true{{ if .SNI }}, \"server_name\": {{ .SNI | quote }}{{ end }}{{ if .AllowInsecure }}, \"insecure\": true{{ end }}{{ if .Fingerprint }}, \"utls\": {\"enabled\": true, \"fingerprint\": {{ .Fingerprint | quote }} }{{ end }}}\n{{- end -}}\n\n{{- define \"NodeOutbound\" -}}\n{{- $n := .n -}}\n{{- $pwd := .UserInfo.Password -}}\n{{- if eq $n.Type \"shadowsocks\" -}}\n{ \"type\": \"shadowsocks\", \"tag\": {{ $n.Name | quote }}, \"server\": {{ $n.Host | quote }}, \"server_port\": {{ $n.Port }}, \"method\": {{ $n.Method | quote }}, \"password\": {{ $pwd | quote }}{{ if $n.ServerKey }}, \"server_key\": {{ $n.ServerKey | quote }}{{ end }}, \"tcp_fast_open\": true }\n{{- else if eq $n.Type \"trojan\" -}}\n{ \"type\": \"trojan\", \"tag\": {{ $n.Name | quote }}, \"server\": {{ $n.Host | quote }}, \"server_port\": {{ $n.Port }}, \"password\": {{ $pwd | quote }}{{ if eq $n.Network \"ws\" }}, {{ template \"WS\" $n }}{{ else if eq $n.Network \"grpc\" }}, {{ template \"GRPC\" $n }}{{ end }}, {{ template \"TLS\" $n }} }\n{{- else if eq $n.Type \"vless\" -}}\n{ \"type\": \"vless\", \"tag\": {{ $n.Name | quote }}, \"server\": {{ $n.Host | quote }}, \"server_port\": {{ $n.Port }}, \"uuid\": {{ $n.ServerKey | quote }}{{ if $n.Flow }}, \"flow\": {{ $n.Flow | quote }}{{ end }}{{ if eq $n.Network \"ws\" }}, {{ template \"WS\" $n }}{{ else if eq $n.Network \"grpc\" }}, {{ template \"GRPC\" $n }}{{ end }}{{ if $n.RealityPublicKey }}, \"reality\": { \"enabled\": true, \"public_key\": {{ $n.RealityPublicKey | quote }}{{ if $n.RealityShortId }}, \"short_id\": {{ $n.RealityShortId | quote }}{{ end }}{{ if $n.SNI }}, \"server_name\": {{ $n.SNI | quote }}{{ end }} }{{ else if or $n.SNI $n.AllowInsecure $n.Fingerprint }}, {{ template \"TLS\" $n }}{{ end }} }\n{{- else if eq $n.Type \"vmess\" -}}\n{ \"type\": \"vmess\", \"tag\": {{ $n.Name | quote }}, \"server\": {{ $n.Host | quote }}, \"server_port\": {{ $n.Port }}, \"uuid\": {{ $n.ServerKey | quote }}, \"security\": \"auto\"{{ if eq $n.Network \"ws\" }}, {{ template \"WS\" $n }}{{ else if eq $n.Network \"grpc\" }}, {{ template \"GRPC\" $n }}{{ end }}{{ if or $n.SNI $n.AllowInsecure $n.Fingerprint }}, {{ template \"TLS\" $n }}{{ end }} }\n{{- else if or (eq $n.Type \"hysteria2\") (eq $n.Type \"hy2\") -}}\n{ \"type\": \"hysteria2\", \"tag\": {{ $n.Name | quote }}, \"server\": {{ $n.Host | quote }}, \"server_port\": {{ $n.Port }}, \"password\": {{ $pwd | quote }}{{ if $n.ObfsPassword }}, \"obfs\": { \"type\": \"salamander\", \"password\": {{ $n.ObfsPassword | quote }} }{{ end }}{{ if $n.HopPorts }}, \"ports\": {{ $n.HopPorts | quote }}{{ end }}{{ if $n.HopInterval }}, \"hop_interval\": {{ $n.HopInterval }}{{ end }}, {{ template \"TLS\" $n }} }\n{{- else if eq $n.Type \"tuic\" -}}\n{ \"type\": \"tuic\", \"tag\": {{ $n.Name | quote }}, \"server\": {{ $n.Host | quote }}, \"server_port\": {{ $n.Port }}, \"uuid\": {{ $n.ServerKey | quote }}, \"password\": {{ $pwd | quote }}{{ if $n.DisableSNI }}, \"disable_sni\": {{ $n.DisableSNI }}{{ end }}{{ if $n.ReduceRtt }}, \"reduce_rtt\": {{ $n.ReduceRtt }}{{ end }}{{ if $n.UDPRelayMode }}, \"udp_relay_mode\": {{ $n.UDPRelayMode | quote }}{{ end }}{{ if $n.CongestionController }}, \"congestion_control\": {{ $n.CongestionController | quote }}{{ end }}, \"alpn\": [\"h3\"], {{ template \"TLS\" $n }} }\n{{- else if eq $n.Type \"anytls\" -}}\n{ \"type\": \"anytls\", \"tag\": {{ $n.Name | quote }}, \"server\": {{ $n.Host | quote }}, \"server_port\": {{ $n.Port }}, \"password\": {{ $pwd | quote }}, {{ template \"TLS\" $n }} }\n{{- else -}}\n{ \"type\": \"direct\", \"tag\": {{ $n.Name | quote }} }\n{{- end -}}\n{{- end -}}\n\n{\n \"log\": {\"level\": \"info\", \"timestamp\": true},\n \"experimental\": {\n \"cache_file\": {\"enabled\": true, \"path\": \"cache.db\", \"cache_id\": \"my_profile\", \"store_fakeip\": false},\n \"clash_api\": {\"external_controller\": \"127.0.0.1:9090\", \"external_ui\": \"ui\", \"secret\": \"\", \"external_ui_download_url\": \"https://mirror.ghproxy.com/https://github.com/MetaCubeX/Yacd-meta/archive/gh-pages.zip\", \"external_ui_download_detour\": \"direct\", \"default_mode\": \"rule\"}\n },\n \"dns\": {\n \"servers\": [\n {\"tag\": \"dns_proxy\",\"address\": \"tls://8.8.8.8\",\"detour\": \"Proxy\"},\n {\"tag\": \"dns_direct\",\"address\": \"https://223.5.5.5/dns-query\",\"detour\": \"direct\"}\n ],\n \"rules\": [\n {\"rule_set\": \"geosite-cn\", \"server\": \"dns_direct\"},\n {\"clash_mode\": \"direct\", \"server\": \"dns_direct\"},\n {\"clash_mode\": \"global\", \"server\": \"dns_proxy\"},\n {\"rule_set\": \"geosite-geolocation-!cn\", \"server\": \"dns_proxy\"}\n ],\n \"final\": \"dns_direct\",\n \"strategy\": \"ipv4_only\"\n },\n \"inbounds\": [\n {\"tag\": \"tun-in\", \"type\": \"tun\", \"address\": [\"172.18.0.1/30\",\"fdfe:dcba:9876::1/126\"], \"auto_route\": true, \"strict_route\": true, \"stack\": \"system\",\n \"platform\": {\"http_proxy\": {\"enabled\": true, \"server\": \"127.0.0.1\", \"server_port\": 7890}}},\n {\"tag\": \"mixed-in\", \"type\": \"mixed\", \"listen\": \"127.0.0.1\", \"listen_port\": 7890}\n ],\n \"outbounds\": [\n {\"tag\": \"Proxy\", \"type\": \"selector\", \"outbounds\": [\"Auto - UrlTest\", \"direct\"{{ if gt (len .Proxies) 0 }}, {{ template \"AllNodeNames\" . }}{{ end }}]},\n {\"tag\": \"Domestic\", \"type\": \"selector\", \"outbounds\": [\"direct\", \"Proxy\"{{ if gt (len .Proxies) 0 }}, {{ template \"AllNodeNames\" . }}{{ end }}]},\n {\"tag\": \"Others\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ if gt (len .Proxies) 0 }}, {{ template \"AllNodeNames\" . }}{{ end }}]},\n {\"tag\": \"AI Suite\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ if gt (len .Proxies) 0 }}, {{ template \"AllNodeNames\" . }}{{ end }}]},\n {\"tag\": \"Netflix\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ if gt (len .Proxies) 0 }}, {{ template \"AllNodeNames\" . }}{{ end }}]},\n {\"tag\": \"Disney Plus\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ if gt (len .Proxies) 0 }}, {{ template \"AllNodeNames\" . }}{{ end }}]},\n {\"tag\": \"YouTube\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ if gt (len .Proxies) 0 }}, {{ template \"AllNodeNames\" . }}{{ end }}]},\n {\"tag\": \"Max\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ if gt (len .Proxies) 0 }}, {{ template \"AllNodeNames\" . }}{{ end }}]},\n {\"tag\": \"Spotify\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ if gt (len .Proxies) 0 }}, {{ template \"AllNodeNames\" . }}{{ end }}]},\n {\"tag\": \"Apple\", \"type\": \"selector\", \"outbounds\": [\"direct\", \"Proxy\"{{ if gt (len .Proxies) 0 }}, {{ template \"AllNodeNames\" . }}{{ end }}]},\n {\"tag\": \"Telegram\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ if gt (len .Proxies) 0 }}, {{ template \"AllNodeNames\" . }}{{ end }}]},\n {\"tag\": \"Microsoft\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ if gt (len .Proxies) 0 }}, {{ template \"AllNodeNames\" . }}{{ end }}]},\n {\"tag\": \"Tiktok\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ if gt (len .Proxies) 0 }}, {{ template \"AllNodeNames\" . }}{{ end }}]},\n\n {\"tag\": \"Auto - UrlTest\", \"type\": \"urltest\", \"outbounds\": [{{ template \"AllNodeNames\" . }}], \"url\": \"http://cp.cloudflare.com/generate_204\", \"interval\": \"10m\", \"tolerance\": 50}\n {{- range $i, $n := .Proxies }},\n {{ template \"NodeOutbound\" (dict \"n\" $n \"UserInfo\" $.UserInfo) }}\n {{- end }}\n {{- if gt (len .Proxies) 0 }},{{ end }}\n\n {\"type\": \"direct\", \"tag\": \"direct\"},\n {\"type\": \"block\", \"tag\": \"block\"}\n ],\n \"route\": {\n \"rules\": [\n {\n \"protocol\": \"dns\",\n \"outbound\": \"dns-out\"\n },\n {\n \"clash_mode\": \"Global\",\n \"outbound\": \"GLOBAL\"\n },\n {\n \"clash_mode\": \"Direct\",\n \"outbound\": \"DIRECT\"\n },\n {\n \"domain_suffix\": [\n \"local\"\n ],\n \"ip_cidr\": [\n \"192.168.0.0/16\",\n \"10.0.0.0/8\",\n \"172.16.0.0/12\",\n \"127.0.0.0/8\",\n \"100.64.0.0/10\"\n ],\n \"outbound\": \"DIRECT\"\n },\n {\n \"domain_suffix\": [\n \"acm.org\",\n \"acs.org\",\n \"aip.org\",\n \"ams.org\",\n \"annualreviews.org\",\n \"aps.org\",\n \"ascelibrary.org\",\n \"asm.org\",\n \"asme.org\",\n \"astm.org\",\n \"blackwell-synergy.com\",\n \"bmj.com\",\n \"cabdirect.org\",\n \"cambridge.org\",\n \"cas.org\",\n \"cell.com\",\n \"clarivate.com\",\n \"csiro.au\",\n \"deepdyve.com\",\n \"ebscohost.com\",\n \"els-cdn.com\",\n \"elsevier.com\",\n \"emerald.com\",\n \"endnote.com\",\n \"engineeringvillage.com\",\n \"icevirtuallibrary.com\",\n \"ieee.org\",\n \"imf.org\",\n \"iop.org\",\n \"jamanetwork.com\",\n \"jbc.org\",\n \"jhu.edu\",\n \"jstor.org\",\n \"karger.com\",\n \"libguides.com\",\n \"liebertpub.com\",\n \"madsrevolution.net\",\n \"mdpi.com\",\n \"mpg.de\",\n \"myilibrary.com\",\n \"nature.com\",\n \"ncbi.nlm.nih.gov\",\n \"oecd-ilibrary.org\",\n \"osapublishing.org\",\n \"oup.com\",\n \"ovid.com\",\n \"oxfordartonline.com\",\n \"oxfordbibliographies.com\",\n \"oxfordmusiconline.com\",\n \"pnas.org\",\n \"proquest.com\",\n \"readcube.com\",\n \"researchgate.net\",\n \"royalsocietypublishing.org\",\n \"rsc.org\",\n \"sagepub.com\",\n \"sci-hub.tw\",\n \"sciencedirect.com\",\n \"science.org\",\n \"scitation.org\",\n \"scopus.com\",\n \"semanticscholar.org\",\n \"siam.org\",\n \"spiedigitallibrary.org\",\n \"springer.com\",\n \"springerlink.com\",\n \"tandfonline.com\",\n \"un.org\",\n \"uni-bielefeld.de\",\n \"webofknowledge.com\",\n \"westlaw.com\",\n \"wiley.com\",\n \"worldbank.org\",\n \"worldscientific.com\"\n ],\n \"outbound\": \"Scholar\"\n },\n {\n \"domain_suffix\": [\n \"a.ckm.iqiyi.com\",\n \"ad.m.iqiyi.com\",\n \"afp.iqiyi.com\",\n \"androidgo.duapp.com\",\n \"api.cupid.iqiyi.com\",\n \"api.cupid.qiyi.com\",\n \"c.uaa.iqiyi.com\",\n \"cloudpush.iqiyi.com\",\n \"cm.passport.iqiyi.com\",\n \"count.game.pps.tv\",\n \"cupid.iqiyi.com\",\n \"emoticon.sns.iqiyi.com\",\n \"game.pps.tv\",\n \"gamecenter.iqiyi.com\",\n \"ifacelog.iqiyi.com\",\n \"mbdlog.iqiyi.com\",\n \"msg.71.am\",\n \"msg.qy.net\",\n \"msg.iqiyi.com\",\n \"msg.video.qiyi.com\",\n \"msg2.video.qiyi.com\",\n \"msga.71.am\",\n \"msga.cupid.iqiyi.com\",\n \"nl.notice.iqiyi.com\",\n \"nl.rcd.iqiyi.com\",\n \"notice.iqiyi.com\",\n \"noxagile.duapp.com\",\n \"paopao.iqiyi.com\",\n \"policy.video.iqiyi.com\",\n \"static.g.iqiyi.com\",\n \"static.g.ppstream.com\",\n \"store.iqiyi.com\",\n \"t7z.cupid.iqiyi.com\",\n \"tracker.sns.iqiyi.com\",\n \"yuedu.iqiyi.com\",\n \"actives.youku.com\",\n \"ad.api.3g.tudou.com\",\n \"ad.api.3g.youku.com\",\n \"ad.api.mobile.youku.com\",\n \"ad.mobile.youku.com\",\n \"a-dxk.play.api.3g.youku.com\",\n \"b.smartvideo.youku.com\",\n \"c.yes.youku.com\",\n \"das.api.youku.com\",\n \"das.mobile.youku.com\",\n \"dev-push.m.youku.com\",\n \"dl.g.youku.com\",\n \"dmapp.youku.com\",\n \"gamex.mobile.youku.com\",\n \"hudong.pl.youku.com\",\n \"huodong.pl.youku.com\",\n \"huodong.vip.youku.com\",\n \"hz.youku.com\",\n \"iyes.youku.com\",\n \"l.ykimg.com\",\n \"lstat.youku.com\",\n \"m.yes.youku.com\",\n \"mobilemsg.youku.com\",\n \"msg.youku.com\",\n \"myes.youku.com\",\n \"p.l.youku.com\",\n \"passport-log.youku.com\",\n \"p-log.ykimg.com\",\n \"push.m.youku.com\",\n \"r.l.youku.com\",\n \"s.p.youku.com\",\n \"sdk.api.gamex.mobile.youku.com\",\n \"sdk.m.youku.com\",\n \"stat.youku.com\",\n \"store.tv.api.3g.youku.com\",\n \"store.xl.api.3g.youku.com\",\n \"tdrec.youku.com\",\n \"test.ott.youku.com\",\n \"urchin.lstat.youku.com\",\n \"v.l.youku.com\",\n \"val.api.youku.com\",\n \"wan.youku.com\",\n \"ykatr.youku.com\",\n \"ykrec.youku.com\",\n \"ads-api.videojj.com\",\n \"cdn.cmop.mgtv.com\",\n \"click.hunantv.com\",\n \"cmop.mgtv.com\",\n \"cytron.videojj.com\",\n \"cytroncdn.videojj.com\",\n \"da.hunantv.com\",\n \"da.mgtv.com\",\n \"imgaliyun.da.mgtv.com\",\n \"imgaliyun.res.mgtv.com\",\n \"m2.da.mgtv.com\",\n \"me.videojj.com\",\n \"mobaliyun.res.mgtv.com\",\n \"mobile.da.mgtv.com\",\n \"mobile2.da.mgtv.com\",\n \"mp4.res.hunantv.com\",\n \"pc.da.mgtv.com\",\n \"pc1.da.mgtv.com\",\n \"pcvideoaliyun.titan.mgtv.com\",\n \"pcvideoyd.titan.mgtv.com\",\n \"pcweb.v1.mgtv.com\",\n \"plat.videojj.com\",\n \"py.da.mgtv.com\",\n \"res.hunantv.com\",\n \"store.videojj.com\",\n \"v2.da.mgtv.com\",\n \"va.videojj.com\",\n \"web.da.mgtv.com\",\n \"x.da.hunantv.com\",\n \"x.da.mgtv.com\",\n \"x1.da.hunantv.com\",\n \"y.da.hunantv.com\",\n \"y.da.mgtv.com\",\n \"1.letvlive.com\",\n \"2.letvlive.com\",\n \"ads1.lfengmobile.com\",\n \"api.game.letvstore.com\",\n \"api.push.le.com\",\n \"ark.letv.com\",\n \"cdn.zampdsp.com\",\n \"cm.fancyapi.com\",\n \"cn.api.push.le.com\",\n \"dc.letv.com\",\n \"fz.letv.com\",\n \"g3.letv.com\",\n \"minisite.letv.com\",\n \"msg.m.letv.com\",\n \"n.mark.letv.com\",\n \"pro.hoye.letv.com\",\n \"pro.letv.com\",\n \"s.zampdsp.com\",\n \"stat.letv.com\",\n \"static.app.m.letv.com\",\n \"webp2p.letv.com\",\n \"zamplus.com\",\n \"azabu-u.ac.jp\",\n \"couchcoaster.jp\",\n \"delivery.dmkt-sp.jp\",\n \"ehg-youtube.hitbox.com\",\n \"m-78.jp\",\n \"nichibenren.or.jp\",\n \"nicorette.co.kr\",\n \"adnet.sohu.com\",\n \"aty.sohu.com\",\n \"epro.sogou.com\",\n \"go.sohu.com\",\n \"golden1.sogou.com\",\n \"imp.optaim.com\",\n \"inte.sogou.com\",\n \"inte.sogoucdn.com\",\n \"lu.sogoucdn.com\",\n \"theta.sogoucdn.com\",\n \"uranus.sogou.com\",\n \"afp.pplive.com\",\n \"app.aplus.pptv.com\",\n \"as.aplus.pptv.com\",\n \"asimgs.pplive.cn\",\n \"de.as.pptv.com\",\n \"jp.as.pptv.com\",\n \"pp2.pptv.com\",\n \"stat.pptv.com\",\n \"static.g.pptv.com\",\n \"deliver.ifeng.com\",\n \"hxjs.tool.hexun.com\",\n \"hxsame.hexun.com\",\n \"itv.hexun.com\",\n \"utrack.hexun.com\",\n \"ad.cmvideo.cn\",\n \"atm.cp31.ott.cibntv.net\",\n \"aty.cp45.ott.cibntv.net\",\n \"cpm.cm.kankan.com\",\n \"float.kankan.com\",\n \"houyi.baofeng.net\",\n \"iadctest.qwapi.com\",\n \"ad.video.51togic.com\",\n \"biz5.kankan.com\",\n \"c.algovid.com\",\n \"cms.laifeng.com\",\n \"da.mmarket.com\",\n \"dotcounter.douyutv.com\",\n \"g.uusee.com\",\n \"gcdn.2mdn.net\",\n \"gentags.net\",\n \"gg.jtertp.com\",\n \"gug.ku6cdn.com\",\n \"hp.smiler-ad.com\",\n \"kooyum.com\",\n \"ld.kuaigames.com\",\n \"logstat.t.sfht.com\",\n \"match.rtbidder.net\",\n \"mixer.cupid.ptqy.gitv.tv\",\n \"msg.c002.ottcn.com\",\n \"msga.ptqy.gitv.tv\",\n \"njwxh.com\",\n \"nl.rcd.ptqy.gitv.tv\",\n \"n-st.vip.com\",\n \"pb.bi.gitv.tv\",\n \"pop.uusee.com\",\n \"rd.kuaigames.com\",\n \"shizen-no-megumi.com\",\n \"shrek.6.cn\",\n \"simba.6.cn\",\n \"st.vq.ku6.cn\",\n \"statcounter.com\",\n \"static.duoshuo.com\",\n \"static.ku6.com\",\n \"static8.pmadx.com\",\n \"store.ptqy.gitv.tv\",\n \"t7z.cupid.ptqy.gitv.tv\",\n \"traffic.uusee.com\",\n \"union.6.cn\",\n \"wa.gtimg.com\",\n \"bfshan.cn\",\n \"0.r.msn.com\",\n \"000dn.com\",\n \"001union.com\",\n \"0086555.com\",\n \"00880808.com\",\n \"00oo00.com\",\n \"01.gxso.net\",\n \"010teacher.com\",\n \"010xk.com\",\n \"018520.com\",\n \"01daa.lubih.com\",\n \"01daa.lutci.com\",\n \"01daa.lutgh.com\",\n \"01daa.luvbr.com\",\n \"01daa.luytr.com\",\n \"022aifang.com\",\n \"023hysj.com\",\n \"025suyu.com\",\n \"0313413.com\",\n \"0451106.com\",\n \"0531kt.com\",\n \"0592weixin.com\",\n \"0594003.com\",\n \"06362.com\",\n \"0756sjlm.com.cn\",\n \"09_19.supfree.net\",\n \"0aqpqdju.me\",\n \"0x01e7.website\",\n \"0xxd.com\",\n \"1.1010pic.com\",\n \"1.201980.com\",\n \"1.21shebao.com\",\n \"1.51sxue.cn\",\n \"1.aili.com\",\n \"1.bashenghuo.com\",\n \"1.chcx.cn\",\n \"1.cjcp.cn\",\n \"1.codesdq.com\",\n \"1.feihua.com\",\n \"1.glook.cn\",\n \"1.hao123.com\",\n \"1.hnyouneng.com\",\n \"1.hslyqs.com\",\n \"1.i1766.com\",\n \"1.iqeq.com.cn\",\n \"1.jeasyui.net\",\n \"1.mgff.com\",\n \"1.nanrenwo.net\",\n \"1.panduoduo.net\",\n \"1.qtmojo.cn\",\n \"1.rengshu.com\",\n \"1.soufy.cn\",\n \"1.tulaoshi.com\",\n \"1.tuxi.com.cn\",\n \"1.win7china.com\",\n \"1.win7sky.com\",\n \"1.wps.cn\",\n \"1.xiaopin5.com\",\n \"1.xiaozhizhijia.com\",\n \"1.xilu.com\",\n \"1.zw3e.com\",\n \"1000dy.com\",\n \"10086.cn.baidu.cdn.yiwk.com\",\n \"100fenlm.com\",\n \"1017.cn\",\n \"10up.com\",\n \"11.hydcd.com\",\n \"111111qb.com\",\n \"111cn.net\",\n \"1133.cc\",\n \"114la.com\",\n \"1178.shucong.com\",\n \"11g.yiqig.cn\",\n \"1224.dxsbb.com\",\n \"123.sogou.com\",\n \"12306media.com\",\n \"1234xm.com\",\n \"12365chia.com\",\n \"123hala.com\",\n \"123juzi.net\",\n \"13023.url.7wkw.com\",\n \"138138138.top\",\n \"142904.com\",\n \"144.dragonparking.com\",\n \"1495039.com\",\n \"163.wrating.com\",\n \"163ren.com\",\n \"168.it168.com\",\n \"1680go.com\",\n \"168ad.cc\",\n \"170yy.com\",\n \"175bar.com\",\n \"176um.com\",\n \"178gg.com\",\n \"17gouwuba.com\",\n \"17leyi.com\",\n \"17un.co\",\n \"17un.com\",\n \"17zhaole.com\",\n \"189zj.cn\",\n \"18av.mm-cg.co\",\n \"18dusun.com\",\n \"18tzx.com\",\n \"1933000.com\",\n \"1d1px.net\",\n \"1e2hyl3b.wq42211.com\",\n \"1i580.com\",\n \"1kmb.cn\",\n \"1kxun.mobi\",\n \"1kzh.com\",\n \"1l1.cc\",\n \"1lib.cn\",\n \"1o26.com\",\n \"1qwe3r.com\",\n \"1tlm.cn\",\n \"1uandun.com\",\n \"1x3x.com\",\n \"2.1010pic.com\",\n \"2.21shebao.com\",\n \"2.5aigushi.com\",\n \"2.aili.com\",\n \"2.bashenghuo.com\",\n \"2.heiyange.com\",\n \"2.mobixs.cn\",\n \"2.nanrenwo.net\",\n \"2.rengshu.com\",\n \"2.tuxi.com.cn\",\n \"201071.com\",\n \"2012.8684.com\",\n \"2012ui.com\",\n \"20150930.cf\",\n \"2016.sina.cn\",\n \"2016bobo.cf\",\n \"2017img.myxh999.com\",\n \"202m.com\",\n \"203710.com\",\n \"2144.cn\",\n \"21union.com\",\n \"22.qingsongbar.com\",\n \"22222jsc.com\",\n \"222627.com\",\n \"22lm.cc\",\n \"233wo.com\",\n \"2345.cn\",\n \"2345api.dftoutiao.com\",\n \"2345apicode.dftoutiao.com\",\n \"2345at.com\",\n \"235123.net\",\n \"24haitao.net\",\n \"256ppp.com\",\n \"268mob.cn\",\n \"272829.cc\",\n \"272xb.com\",\n \"285680.com\",\n \"28acglz.com\",\n \"2a.com.cn\",\n \"2cnt.net\",\n \"2m2n.com\",\n \"2o7.net\",\n \"3.guidaye.com\",\n \"3.ssqzj.com\",\n \"30350f.com\",\n \"30407799.com\",\n \"30ampj.com\",\n \"31.media.tumblr.com\",\n \"312036.com\",\n \"3180555.com\",\n \"32414.com\",\n \"32666099.com\",\n \"33.pcpop.com\",\n \"33544444.com\",\n \"336.com\",\n \"3388pjdc.com\",\n \"339.cn\",\n \"3393.com\",\n \"33lm.cc\",\n \"33shangyou.com\",\n \"35baba.cn\",\n \"3600.com\",\n \"360640.com\",\n \"360baidus.com\",\n \"360jiaquan.com\",\n \"360safego.com\",\n \"360shopping.com.cn\",\n \"360vip.front99.com\",\n \"361315.cc\",\n \"365bibi.com\",\n \"365safego.com\",\n \"366safego.com\",\n \"36pn.com\",\n \"3721zh.com\",\n \"376zf.com\",\n \"37cs.com\",\n \"37mnm.com\",\n \"37pk49.com\",\n \"37see.com\",\n \"37wan.cn\",\n \"37wan.com\",\n \"3808010.com\",\n \"38330.bet\",\n \"3839168.com\",\n \"38499.com\",\n \"38c99.com\",\n \"39330.bet\",\n \"3975lm.com\",\n \"39xc.net\",\n \"3dm.huya.com\",\n \"3dns-2.adobe.com\",\n \"3dns-3.adobe.com\",\n \"3dwwwgame.com\",\n \"3g.990.net\",\n \"3gmimo.com\",\n \"3gmtr.com\",\n \"3htai.com\",\n \"3qmh.com\",\n \"3rd.t.sohu.com\",\n \"3wz6z.bchuangpi.cn\",\n \"3ygww.com\",\n \"4009997658.com\",\n \"404.safedog.cn\",\n \"4207008.com\",\n \"4242jj.com\",\n \"4242lll.com\",\n \"4242uuu.com\",\n \"4336wang.cn\",\n \"456juhd.com\",\n \"46sg.com\",\n \"49wanwan.com\",\n \"4ggww.com\",\n \"4paradigm.com\",\n \"4wad.com\",\n \"4xhyr.shuimujinggong.com\",\n \"504pk.com\",\n \"5066.net\",\n \"50bang.org\",\n \"51.la\",\n \"5125129.com\",\n \"513hch.com\",\n \"517m.cn\",\n \"518.sdinfo.net\",\n \"5188yy.com\",\n \"519397.com\",\n \"51ads.com\",\n \"51chumoping.com\",\n \"51dql.com\",\n \"51gxqm.com\",\n \"51jumintong.com\",\n \"51la.net\",\n \"51link.com\",\n \"51mld.cn\",\n \"51network.com\",\n \"51vipedu.com\",\n \"51weidashi.com\",\n \"51xumei.com\",\n \"51yes.com\",\n \"51zhanzhuang.cn\",\n \"5207470.com\",\n \"5269120.com\",\n \"526d.uunice.com\",\n \"526dimg.uunice.com\",\n \"5293.com\",\n \"52kmh.com\",\n \"52kmk.com\",\n \"52lubo.cn\",\n \"5345ll.com\",\n \"537901.com\",\n \"55.la\",\n \"555p555p.com\",\n \"559gp.com\",\n \"55lu.com\",\n \"5634.com\",\n \"5675146.com\",\n \"57.com.cn\",\n \"57union.com\",\n \"58.xgo.com.cn\",\n \"5814889.com\",\n \"5857.com\",\n \"588yw.com\",\n \"58lm.vip\",\n \"58mingri.cn\",\n \"58mingtian.cn\",\n \"592man.com\",\n \"5dg.me\",\n \"5dian.org\",\n \"5egk.com\",\n \"5imoney.com\",\n \"5jcom.com.cn\",\n \"5vz3cfs0yd.me\",\n \"5y9nfpes.52pk.com\",\n \"5yrra.deshuangwang.cn\",\n \"600ad.com\",\n \"601654.com\",\n \"60608787.com\",\n \"626uc.com\",\n \"644446.com\",\n \"649558.com\",\n \"64si.com\",\n \"654mmm.com\",\n \"6615338.cn\",\n \"6666349.com\",\n \"6669667.com\",\n \"66992949.com\",\n \"66san.com\",\n \"6711.com\",\n \"6728812.com\",\n \"685wo.com\",\n \"68665565.com\",\n \"69duk.com\",\n \"6a4cc.lubue.com\",\n \"6a4cc.luvbq.com\",\n \"6a4cc.luvbr.com\",\n \"6a4cc.luytr.com\",\n \"6boou.voluumtrk.com\",\n \"6d63d3.com\",\n \"6dad.com\",\n \"6dvip.com\",\n \"6huu.com\",\n \"6kwan.com\",\n \"6tsbe1zs.me\",\n \"700900.com\",\n \"706529.com\",\n \"7080555.com\",\n \"70e.com\",\n \"70lm.com\",\n \"711kk.com\",\n \"716703.com\",\n \"71sem.com\",\n \"73.sinawap.com\",\n \"743m1.11a12.com\",\n \"749558.com\",\n \"749808.com\",\n \"7540.com\",\n \"75to.com\",\n \"7631.com\",\n \"766ba.net\",\n \"76802.net\",\n \"77455.com\",\n \"778669.com\",\n \"7794.com\",\n \"77power.com\",\n \"77u.com\",\n \"77xtv.com\",\n \"7891655.cn\",\n \"7car.com.cn\",\n \"7clink.com\",\n \"7dah8.com\",\n \"7gg.cc\",\n \"7jiajiao.com\",\n \"7mad.7m.cn\",\n \"7pk.com\",\n \"7wen.cn\",\n \"7xz3.com\",\n \"7z66.com\",\n \"8.jrj.com\",\n \"801.tianyaui.com\",\n \"8066hg.com\",\n \"80sjw.com\",\n \"813690.top\",\n \"8184.cc\",\n \"818mov.com\",\n \"81c.cn\",\n \"8269996.com\",\n \"8368661.com\",\n \"846.move7.com\",\n \"849558.com\",\n \"85058s.com\",\n \"8521448.com\",\n \"85655095.com\",\n \"859377.com\",\n \"85tgw.com\",\n \"86.cc\",\n \"860010.com\",\n \"86kx.com\",\n \"878090.com\",\n \"8800271.com.cn\",\n \"88210212.com\",\n \"8866786.com\",\n \"888.izhufu.net\",\n \"888.jiuwanwang.com\",\n \"888.tv.sohu.com\",\n \"88818122.cn\",\n \"888zr022.com\",\n \"88cncc.com\",\n \"88rpg.net\",\n \"88shu.cn\",\n \"892155.com\",\n \"89h8.com\",\n \"8dulm.com\",\n \"8hykthze.cricket\",\n \"8jd2lfsq.me\",\n \"8jkx.com\",\n \"8le8le.com\",\n \"8mfty.com\",\n \"8ox.cn\",\n \"90053999.com\",\n \"910weixin.com\",\n \"911.cc\",\n \"915.com\",\n \"91ad.bestvogue.com\",\n \"91adv.com\",\n \"91hui.com\",\n \"91veg.com\",\n \"91xry.com\",\n \"91ysa.com\",\n \"91zgm.com\",\n \"92x.tumblr.com\",\n \"930.dragonparking.com\",\n \"93manhua.com\",\n \"94lm.com\",\n \"95105012.com\",\n \"9519.net\",\n \"95558000.com\",\n \"9565365.com\",\n \"9566180.com\",\n \"96mob.com\",\n \"9948000.com\",\n \"99909988.com\",\n \"99click.com\",\n \"99ddd.com\",\n \"99lolo.com\",\n \"9ads.net\",\n \"9dtiny.cn\",\n \"9kff.com\",\n \"9pkw.com\",\n \"9s6q.cn\",\n \"9tn.cc\",\n \"9wushuo.com\",\n \"a.198banjia.com\",\n \"a.53yao.com\",\n \"a.5ykj.com\",\n \"a.80982.org\",\n \"a.ads1.msn.com\",\n \"a.ads2.msn.com\",\n \"a.armystar.com\",\n \"a.baidu.com\",\n \"a.baiy.net\",\n \"a.baomihua.com\",\n \"a.beilamusi.com\",\n \"a.benshiw.net\",\n \"a.bshu.com\",\n \"a.cdngeek.net\",\n \"a.clipconverter.cc\",\n \"a.cn.duoyi.com\",\n \"a.dangdang.com\",\n \"a.dianjoy.com\",\n \"a.dounanhuahui.com\",\n \"a.duanmeiwen.com\",\n \"a.e7009.com\",\n \"a.ecook.cn\",\n \"a.epinv.com\",\n \"a.eporner.com\",\n \"a.exam58.com\",\n \"a.fengyx.com\",\n \"a.fwsir.com\",\n \"a.giantrealm.com\",\n \"a.global.msads.net\",\n \"a.hl.mi.com\",\n \"a.holagames.com\",\n \"a.irs01.com\",\n \"a.itiexue.net\",\n \"a.jyeoo.com\",\n \"a.kandiaoyu.com\",\n \"a.kejixun.com\",\n \"a.kickass.to\",\n \"a.koudai.com\",\n \"a.livesportmedia.eu\",\n \"a.lolwot.com\",\n \"a.ltdnc.com\",\n \"a.lwinl.com\",\n \"a.lz13.cn\",\n \"a.m.gxwztv.com\",\n \"a.m.shuhuangge.org\",\n \"a.mct01.com\",\n \"a.mjlnbx.cn\",\n \"a.nanhuwang.com\",\n \"a.nowscore.com\",\n \"a.qiao024.com\",\n \"a.qinghua5.com\",\n \"a.shangz99991.com\",\n \"a.shczz.com\",\n \"a.shenchuang.com\",\n \"a.shuoshuodaquan.net\",\n \"a.solarmovie.is\",\n \"a.soonyou123.com\",\n \"a.starstar19999.com\",\n \"a.startui19999.com\",\n \"a.thefreethoughtproject.com\",\n \"a.tribalfusion.com\",\n \"a.tujidao.com\",\n \"a.tuuituii2999.com\",\n \"a.ucoz.net\",\n \"a.union.mi.com\",\n \"a.visualrevenue.com\",\n \"a.vlion.cn\",\n \"a.waczt.cn\",\n \"a.wlfnb.com\",\n \"a.xinwenge.net\",\n \"a.xixiyishu.com\",\n \"a.xizi.com\",\n \"a.xywy.com\",\n \"a.yangshengtang123.com\",\n \"a.yixie8.com\",\n \"a.yjbys.com\",\n \"a.youdao.com\",\n \"a1.0s.net.cn\",\n \"a1.azg168.cn\",\n \"a1.gexing.me\",\n \"a1.huanqiumil.com\",\n \"a1.huiqituan.com\",\n \"a1.itc.cn\",\n \"a1.liuxue86.com\",\n \"a1.lmaq.cn\",\n \"a1.peoplecdn.cn\",\n \"a1.vdolady.com\",\n \"a1.yuuedu.com\",\n \"a1.zhanzhang.net\",\n \"a1click.cpc.sogou.com\",\n \"a2.b310.com\",\n \"a2.huanqiumil.com\",\n \"a2.rabbitpre.com\",\n \"a3.ikafan.com\",\n \"a3p4.net\",\n \"a4.b2b168.com\",\n \"a4.ikafan.com\",\n \"a4.yeshj.com\",\n \"a5.yeshj.com\",\n \"a6.bjdianyue.com\",\n \"a6.codejumps.com\",\n \"a6.taobanapp.com\",\n \"a6s.1cakeclub.com\",\n \"a6s.modoupai.com\",\n \"a6s.ruyiqufu.com\",\n \"a6s.ve001nz.com\",\n \"a7shun.com\",\n \"a907907.com\",\n \"a9377j.com\",\n \"aa.goodsblock.mgid.com\",\n \"aa.jiankang.com\",\n \"aa.tianya999.com\",\n \"aa.xiangxiangmf.com\",\n \"aa.zldh123.com\",\n \"aa0.pub.funshion.com\",\n \"aa1.pub.funshion.com\",\n \"aafanke.cc\",\n \"aa-gb.mgid.com\",\n \"aam.adsremote.scrippsnetworks.com\",\n \"ab.dydab.com\",\n \"ab.goodsblock.mgid.com\",\n \"ab.hysdknb.com\",\n \"ab.meishiba.com.cn\",\n \"ab.sc115.com\",\n \"abbyychina.com\",\n \"abc.dooccn.com\",\n \"abc.douguo.com\",\n \"abc.eastlady.cn\",\n \"abc.hkepc.com\",\n \"abc.ruiwen.com\",\n \"abc.xtyx918.com\",\n \"abc.yjbys.com\",\n \"abc.zhiyaspa.com\",\n \"abcd.zsrt88.cn\",\n \"abcj.dooccn.com\",\n \"ab-gb.mgid.com\",\n \"abtest.mistat.xiaomi.com\",\n \"ac.atpanel.com\",\n \"ac2.msn.com\",\n \"ac3.msn.com\",\n \"acasys88.cn\",\n \"access.njherald.com\",\n \"ac-gb.mgid.com\",\n \"acint.net\",\n \"acm.dzwww.com\",\n \"acs86.com\",\n \"acsystem.wasu.cn\",\n \"act2.mediafour.com\",\n \"activate.adobe.com\",\n \"activate.wip3.adobe.com\",\n \"activate-sea.adobe.com\",\n \"activate-sjc0.adobe.com\",\n \"activation.cyberlink.com\",\n \"activation.easeus.com\",\n \"active.baofeng.com\",\n \"activeqq.3g.qq.com\",\n \"activity.serving-sys.com\",\n \"activity.tuifish.com\",\n \"activity.yuyiya.com\",\n \"actlog.dftoutiao.com\",\n \"actsdk.idreamsky.com\",\n \"acuityplatform.com\",\n \"acwgf.com\",\n \"acxiom-online.com\",\n \"ad.1111cpc.com\",\n \"ad.12306.cn\",\n \"ad.17173.com\",\n \"ad.1kxun.com\",\n \"ad.3.cn\",\n \"ad.360yield.com\",\n \"ad.363.in\",\n \"ad.3dnews.ru\",\n \"ad.51wnl.com\",\n \"ad.95306.cn\",\n \"ad.about.co.kr\",\n \"ad.accessmediaproductions.com\",\n \"ad.adhouyi.cn\",\n \"ad.aidalan.com\",\n \"ad.api.moji.com\",\n \"ad.auditude.com\",\n \"ad.bayescom.com\",\n \"ad.beihai365.com\",\n \"ad.bitmedia.io\",\n \"ad.bjmama.net\",\n \"ad.cacafly.com\",\n \"ad.cctv.com\",\n \"ad.cooks.com\",\n \"ad.crichd.in\",\n \"ad.csdn.net\",\n \"ad.dedecms.com\",\n \"ad.digitimes.com.tw\",\n \"ad.directmirror.com\",\n \"ad.dokrmob.com\",\n \"ad.doubanio.com\",\n \"ad.download.cnet.com\",\n \"ad.dqwjzm.com\",\n \"ad.duapps.com\",\n \"ad.duga.jp\",\n \"ad.dumedia.ru\",\n \"ad.duomi.com\",\n \"ad.dzwindows.com\",\n \"ad.dzwww.com\",\n \"ad.egou.com\",\n \"ad.endpo.in\",\n \"ad.epochtimes.com\",\n \"ad.eporner.com\",\n \"ad.evozi.com\",\n \"ad.flipboard.com\",\n \"ad.flurry.com\",\n \"ad.flux.com\",\n \"ad.fnnews.com\",\n \"ad.foxnetworks.com\",\n \"ad.funp.com\",\n \"ad.funshion.org.cn\",\n \"ad.gametower.com.tw\",\n \"ad.ganji.com\",\n \"ad.gmw.cn\",\n \"ad.go.com\",\n \"ad.greedland.net\",\n \"ad.gtbrowser.com\",\n \"ad.hefei.cc\",\n \"ad.hiiir.com\",\n \"ad.holaq.com\",\n \"ad.hot-mob.com\",\n \"ad.house365.com\",\n \"ad.huajiao.com\",\n \"ad.ibookstar.com\",\n \"ad.icasthq.com\",\n \"ad.idgtn.net\",\n \"ad.iloveinterracial.com\",\n \"ad.ipadview.com\",\n \"ad.jamba.net\",\n \"ad.jamster.co.uk\",\n \"ad.jamster.com\",\n \"ad.jiemian.com\",\n \"ad.jsnbrynb.com\",\n \"ad.jxnews.com.cn\",\n \"ad.kissanime.io\",\n \"ad.kisscartoon.io\",\n \"ad.leadbolt.net\",\n \"ad.leadboltads.net\",\n \"ad.leadboltapps.net\",\n \"ad.leadboltmobile.net\",\n \"ad.livere.co.kr\",\n \"ad.lqalm.com\",\n \"ad.lyricswire.com\",\n \"ad.madserving.com\",\n \"ad.mail.ru\",\n \"ad.mail.sohu.com\",\n \"ad.mangareader.net\",\n \"ad.mediabong.net\",\n \"ad.mesomorphosis.com\",\n \"ad.mi.com\",\n \"ad.mnt123.com\",\n \"ad.molitv.cn\",\n \"ad.naver.com\",\n \"ad.netowl.jp\",\n \"ad.newegg.com\",\n \"ad.obuy.tw\",\n \"ad.openmultimedia.biz\",\n \"ad.outsidehub.com\",\n \"ad.pandora.tv\",\n \"ad.pchome.com.tw\",\n \"ad.pickple.net\",\n \"ad.pixnet.in\",\n \"ad.pixnet.net\",\n \"ad.player.baidu.com\",\n \"ad.propellerads.com\",\n \"ad.proxy.sh\",\n \"ad.qingting.fm\",\n \"ad.qq.com\",\n \"ad.r.worldssl.net\",\n \"ad.rambler.ru\",\n \"ad.reachlocal.com\",\n \"ad.rednet.cn\",\n \"ad.reklamport.com\",\n \"ad.search.ch\",\n \"ad.seeyouyima.com\",\n \"ad.sensismediasmart.com.au\",\n \"ad.services.distractify.com\",\n \"ad.shuoshuomi.com\",\n \"ad.sina.com.cn\",\n \"ad.sinovision.net\",\n \"ad.slutload.com\",\n \"ad.smartclip.net\",\n \"ad.sohu.com\",\n \"ad.spielothek.so\",\n \"ad.spreaker.com\",\n \"ad.stsywl.com\",\n \"ad.tatatimes.com\",\n \"ad.test.ximalaya.com\",\n \"ad.thepaper.cn\",\n \"ad.thisav.com\",\n \"ad.thsi.cn\",\n \"ad.toutiao.com\",\n \"ad.turn.com\",\n \"ad.unimhk.com\",\n \"ad.userporn.com\",\n \"ad.vidaroo.com\",\n \"ad.vryeye.com\",\n \"ad.walkgame.com\",\n \"ad.wang502.com\",\n \"ad.winningpartner.com\",\n \"ad.winrar.com.cn\",\n \"ad.wretch.cc\",\n \"ad.xiaomi.com\",\n \"ad.ximalaya.com\",\n \"ad.xmovies8.ru\",\n \"ad.xxguan.cn\",\n \"ad.yeshitv.com\",\n \"ad.yieldlab.net\",\n \"ad.yixin.im\",\n \"ad.ylunion.com\",\n \"ad.zanox.com\",\n \"ad.zdworks.com\",\n \"ad.zhangyue.com\",\n \"ad.zhidian3g.cn\",\n \"ad.zuimeitianqi.com\",\n \"ad0.bigmir.net\",\n \"ad000000.com\",\n \"ad1.bigmir.net\",\n \"ad1.greedland.net\",\n \"ad1.nend.net\",\n \"ad1.netshelter.net\",\n \"ad1.p5w.net\",\n \"ad1.udn.com\",\n \"ad1.xiaomi.com\",\n \"ad1.yangjinyou.com\",\n \"ad2.nend.net\",\n \"ad2.udn.com\",\n \"ad2.yam.com\",\n \"ad2.yangjinyou.com\",\n \"ad3.udn.com\",\n \"ad4.bigmir.net\",\n \"ad4.sina.com.cn\",\n \"ad4.udn.com\",\n \"ad4game.com\",\n \"ad5.bigmir.net\",\n \"ad6.bigmir.net\",\n \"ad7.bigmir.net\",\n \"ad7.com\",\n \"ad7.on.cc\",\n \"ad7.tagphi.net\",\n \"ad8.adfarm1.adition.com\",\n \"ad9377.com\",\n \"adadapted.com\",\n \"adadmin.house365.com\",\n \"adadvisor.net\",\n \"ad-android.51wnl.com\",\n \"adap.tv\",\n \"adapi.lenovogame.com\",\n \"adasad.myweb.hinet.net\",\n \"adash.m.taobao.com\",\n \"adbana.com\",\n \"ad-beta.flipboard.com\",\n \"adbot.tw\",\n \"adbox.sina.com.cn\",\n \"ad-brix.com\",\n \"adbuyer3.lycos.com\",\n \"adbxb.com\",\n \"adcast.deviantart.com\",\n \"adcast.fblife.com\",\n \"adccoo.cn\",\n \"adcdn.goo.ne.jp\",\n \"adchina.com\",\n \"adcitrus.com\",\n \"adcl.pchome.com.tw\",\n \"adclick.g.doublecklick.net\",\n \"adclient.uimserv.net\",\n \"adclock.zdworks.com\",\n \"adcloud.jp\",\n \"ad-cloud.jp\",\n \"ad-cn.jovcloud.com\",\n \"adcolony.com\",\n \"adcome.cn\",\n \"adcore.lenovomm.com\",\n \"adcount.yoka.com\",\n \"adcr.naver.com\",\n \"adcreative.naver.com\",\n \"add.bugun.com.tr\",\n \"add.dz19.net\",\n \"add.freeimg8.com\",\n \"add.mmyuer.com\",\n \"addata.ku6.com\",\n \"ad-delivery.net\",\n \"addirector.vindicosuite.com\",\n \"addl.easetuner.com\",\n \"adds.weatherology.com\",\n \"addthis.com\",\n \"addthisedge.com\",\n \"adeaz.com\",\n \"ader.mobi\",\n \"adeventtracker.spotify.com\",\n \"adexprt.com\",\n \"adf.dahe.cn\",\n \"adfarm.mediaplex.com\",\n \"adform.net\",\n \"adfront.auction.co.kr\",\n \"adfurikun.jp\",\n \"adfuture.cn\",\n \"ad-gb.mgid.com\",\n \"adgeo.163.com\",\n \"adhai.com\",\n \"adhome.1fangchan.com\",\n \"adhouyi.com\",\n \"adi.bigmir.net\",\n \"adi.cnool.net\",\n \"adi2007.cnool.net\",\n \"adimages.go.com\",\n \"adimages.sina.com.hk\",\n \"adimg.bbcss.com\",\n \"adimg.cqnews.net\",\n \"adimg.daumcdn.net\",\n \"adimg.deviantart.net\",\n \"adimg.mobile.sina.cn\",\n \"adimg.qxlsjw.com\",\n \"adimg.uimserv.net\",\n \"adimg.uve.weibo.com\",\n \"adimg1.chosun.com\",\n \"adimg3.search.naver.net\",\n \"adimgs.xici.net\",\n \"adimp.excite.co.jp\",\n \"adinall.com\",\n \"adinf.cp11.ott.cibntv.net\",\n \"adinf.voole.com\",\n \"adinfo.aol.com\",\n \"adinfo.ra1.xlmc.sec.miui.com\",\n \"adinfuse.com\",\n \"adingo.jp.eimg.jp\",\n \"adirects.com\",\n \"adjb.5nd.com\",\n \"adjust.io\",\n \"adk.funshion.com\",\n \"adk2.co\",\n \"adk2x.com\",\n \"adkmob.com\",\n \"adkongjian.com\",\n \"adlabs-sync.rutarget.ru\",\n \"adlaunch.moji.com\",\n \"adlefee.com\",\n \"adlink.shopsafe.co.nz\",\n \"adlive.cn\",\n \"adlocus.com\",\n \"ad-locus.com\",\n \"adlog.flurry.com\",\n \"adm.10jqka.com.cn\",\n \"adm.265g.com\",\n \"adm.72zx.com\",\n \"adm.86wan.com\",\n \"adm.baidu.com\",\n \"adm.cloud.cnfol.com\",\n \"adm.easou.com\",\n \"adm.funshion.com\",\n \"adm.icast.cn\",\n \"adm.leju.com\",\n \"adm.leju.sina.com.cn\",\n \"adm.myzaker.com\",\n \"adm.xmfish.com\",\n \"adm.zbinfo.net\",\n \"adm.zookingsoft.com\",\n \"adm0.autoimg.cn\",\n \"adm1.autoimg.cn\",\n \"adm2.autoimg.cn\",\n \"adm3.autoimg.cn\",\n \"admaji.com\",\n \"admarket.21cn.com\",\n \"admarket.mobi\",\n \"admd.yam.com\",\n \"admedia.com\",\n \"admeta.vo.llnwd.net\",\n \"admgr.qingting.fm\",\n \"admin.cooguo.com\",\n \"admin.louxia.org\",\n \"admin.ninebox.cn\",\n \"admin6.com\",\n \"admon.cn\",\n \"admtpmp124.com\",\n \"admx.baixing.com\",\n \"adn.ebay.com\",\n \"adn.insight.ucweb.com\",\n \"adnetpub.yaolan.com\",\n \"adnew.wifi8.com\",\n \"adnxs.com\",\n \"adobe-dns.adobe.com\",\n \"adobe-dns-2.adobe.com\",\n \"adobe-dns-3.adobe.com\",\n \"adomv.com\",\n \"adp.cnool.net\",\n \"adp.s8bbs.com\",\n \"adp1.cnool.net\",\n \"adpai.thepaper.cn\",\n \"adperium.com\",\n \"adping.qq.com\",\n \"adplatform.vrtcal.com\",\n \"ad-plus.cn\",\n \"adplus.goo.mx\",\n \"adplxmd.com\",\n \"adpm.app.qq.com\",\n \"adpolestar.net\",\n \"adpro.cn\",\n \"adpro.pro.cn\",\n \"adpub.yaolan.com\",\n \"adpublish.ydstatic.com\",\n \"adpubs.yaolan.com\",\n \"adpush.cn\",\n \"adq.chinaso.com\",\n \"adrdir.qq.com\",\n \"adreal.cn\",\n \"adres.myaora.net\",\n \"adriver.ru\",\n \"adriver-sync.rutarget.ru\",\n \"adroll.com\",\n \"adrotator.se\",\n \"adrs.sdo.com\",\n \"adrunnr.com\",\n \"ads1.msads.net\",\n \"ads1.msn.com\",\n \"ads2.contentabc.com\",\n \"ads2.msads.net\",\n \"ads2.msn.com\",\n \"ads2.opensubtitles.org\",\n \"ads8.com\",\n \"ads80.com\",\n \"adsame.com\",\n \"adsapi.manhuaren.com\",\n \"adsatt.abcnews.starwave.com\",\n \"adsatt.disney.starwave.com\",\n \"adsatt.espn.go.com\",\n \"adsatt.espn.starwave.com\",\n \"adsatt.familyfun.starwave.com\",\n \"adsatt.go.starwave.com\",\n \"adsatt.movies.starwave.com\",\n \"adscaspion.appspot.com\",\n \"adscdn.baidu.com\",\n \"adsclick.qq.com\",\n \"adsclick.yx.js.cn\",\n \"adsco.re\",\n \"adscript.gmarket.co.kr\",\n \"adsdk.9imobi.com\",\n \"adsdk.dmzj.com\",\n \"adse.test.ximalaya.com\",\n \"adse.ximalaya.com\",\n \"adsence.sogou.com\",\n \"adsense.html5.qq.com\",\n \"adserve2.tom.com\",\n \"adsfactor.net\",\n \"adsfile.bssdlbig.kugou.com\",\n \"adsfile.qq.com\",\n \"adsfs.oppomobile.com\",\n \"adsgroup.qq.com\",\n \"adshare.freedocast.com\",\n \"adshmct.qq.com\",\n \"adshmmsg.qq.com\",\n \"adshost2.com\",\n \"adshow.58.com\",\n \"adshow.it168.com\",\n \"adshows.21cn.com\",\n \"adsin.zhangyoubao.com\",\n \"adsinstant.com\",\n \"adslvfile.qq.com\",\n \"adslvseed.qq.com\",\n \"adsmart.yicha.cn\",\n \"adsolution.imtt.qq.com\",\n \"adsor.openrunner.com\",\n \"adsp.xunlei.com\",\n \"ad-specs.guoshipartners.com\",\n \"adsqqclick.qq.com\",\n \"adsremote.scrippsnetworks.com\",\n \"adsrvr.org\",\n \"adss.dotdo.net\",\n \"adss.yahoo.com\",\n \"adstat.cp11.ott.cibntv.net\",\n \"adstextview.qq.com\",\n \"adstil.indiatimes.com\",\n \"ad-stir.com\",\n \"adsmind.gdtimg.com\",\n \"adstream.123.sogoucdn.com\",\n \"ads-twitter.com\",\n \"ads-v-darwin.hulustream.com\",\n \"adsunflower.com\",\n \"adsunion.com\",\n \"ad-survey.com\",\n \"adsview.qq.com\",\n \"adsview2.qq.com\",\n \"adsymptotic.com\",\n \"adsyndication.msn.com\",\n \"adsys.chinacloudapp.cn\",\n \"adsys.sinovision.net\",\n \"adtaily.com\",\n \"ad-tech.nbcuni.com\",\n \"adtechjp.com\",\n \"adtechus.com\",\n \"adtest.theonion.com\",\n \"adthor.com\",\n \"adtrack.ucweb.com\",\n \"adtrk.me\",\n \"adui.tg.meitu.com\",\n \"adultfriendfinder.com\",\n \"adups.com\",\n \"aduu.cn\",\n \"adv.app.qq.com\",\n \"adv.ccb.com\",\n \"adv.fjtv.net\",\n \"adv.jxnews.com.cn\",\n \"adv.madserving.com\",\n \"adv.s8bbs.com\",\n \"adv.sec.miui.com\",\n \"adv2.downsave.com\",\n \"advapi.ahtv.cn\",\n \"adver.qq.com\",\n \"adview.cn\",\n \"advmob.cn\",\n \"advombat.ru\",\n \"adwasu.wasu.tv\",\n \"adweb.test.ximalaya.com\",\n \"adweb.ximalaya.com\",\n \"adwhirl.com\",\n \"adwo.com\",\n \"adx.adxglobal.com\",\n \"adx.chip.de\",\n \"adx.dlads.cn\",\n \"adx.kat.ph\",\n \"adx.pro.cn\",\n \"adx.xiaodutv.com\",\n \"adx3.iq39.com\",\n \"adxmi.com\",\n \"adxpansion.com\",\n \"adxserver.ad.cmvideo.cn\",\n \"adytx.com\",\n \"adyun.com\",\n \"adz.zwee.ly\",\n \"adzerk.net\",\n \"aec.shjk123.net\",\n \"aecpm.alicdn.com\",\n \"ae-gb.mgid.com\",\n \"aercxy.com\",\n \"aerserv.com\",\n \"aes01.com\",\n \"afd.baidu.com\",\n \"afd.l.google.com\",\n \"aff.eteachergroup.com\",\n \"aff.lmgtfy.com\",\n \"aff.marathonbet.com\",\n \"aff.svjump.com\",\n \"affil.mupromo.com\",\n \"affiliategroove.com\",\n \"affiliateprogram.keywordspy.com\",\n \"affiliates.allposters.com\",\n \"affiliates.goodvibes.com\",\n \"affiliates.thrixxx.com\",\n \"affiliatesmedia.sbobet.com\",\n \"affiliation.fotovista.com\",\n \"afjlb.com\",\n \"afp.alicdn.com\",\n \"afp.chinanews.com\",\n \"afp.csbew.com\",\n \"afp.m1905.com\",\n \"afp.wasu.cn\",\n \"afp.zol-img.com.cn\",\n \"afpcreative.wasu.cn\",\n \"afpimages.eastday\",\n \"afpimages.eastday.com\",\n \"afpmm.alicdn.com\",\n \"afptrack.csbew.com\",\n \"ag.nukefans.net\",\n \"agenda.complex.com\",\n \"ag-gb.marketgid.com\",\n \"agn.aty.cp45.ott.cibntv.net\",\n \"agn.aty.snmsohu.aisee.tv\",\n \"agoodm.m.taobao.com\",\n \"agr.voiceads.cn\",\n \"agrant.cn\",\n \"agrantsem.com\",\n \"ahhuazhen.com\",\n \"ahyau.com\",\n \"ahyuns.com\",\n \"ai.bioon.com\",\n \"ai.m.taobao.com\",\n \"ai.taobao.com\",\n \"ai.xinju.cc\",\n \"ai.yimg.jp\",\n \"aibangzs.com\",\n \"aiclk.com\",\n \"aicydb.com\",\n \"aid.chinayk.com\",\n \"aider-res.meizu.com\",\n \"aihaoduo.cn\",\n \"aikan6.com\",\n \"ailicee.com\",\n \"aim.yoyi.com.cn\",\n \"air.yoyi.com.cn\",\n \"airpush.com\",\n \"airpushmarketing.s3.amazonaws.com\",\n \"ais.abacast.com\",\n \"aishang.bid\",\n \"aishiguolong.com\",\n \"aishowbger.com\",\n \"aiwen.cc\",\n \"ajapk.com\",\n \"ajaxcdn.org\",\n \"aj-gb.mgid.com\",\n \"ajhdf.com\",\n \"ajialive.com\",\n \"ajnad.aljazeera.net\",\n \"ajuhd.com\",\n \"ak.sascdn.com\",\n \"ak47.cooguo.com\",\n \"akrwi.cn\",\n \"akuai.top\",\n \"akxsrsdbursfpx.bid\",\n \"alertserver.ushaqi.com\",\n \"alipay.dajiadou6.com\",\n \"aliqqjd.cn\",\n \"alisinak.com\",\n \"alissl.ucdl.pp.uc.cn\",\n \"alistatic.cn\",\n \"alitianxia168.com\",\n \"alitui.weibo.com\",\n \"aliunion.cn.yahoo.com\",\n \"aliyuncss.com\",\n \"aliyunxin.com\",\n \"all.orfr.adgtw.orangeads.fr\",\n \"all.rising.com.cn\",\n \"allnews.uodoo.com\",\n \"allxin.com\",\n \"als.baidu.com\",\n \"alvares.esportsheaven.com\",\n \"am.6park.com\",\n \"am.g.ireader.com\",\n \"am.szhome.com\",\n \"am.zdnet.com.cn\",\n \"am15.net\",\n \"amazingmagics.com\",\n \"amazon-adsystem.com\",\n \"amdc.m.taobao.com\",\n \"amfi.gou.sogou.com\",\n \"amiok.org\",\n \"amps.yoyi.com.cn\",\n \"ams.fx678.com\",\n \"ams.lenovomm.com\",\n \"a-m-s.poco.cn\",\n \"amz.steamprices.com\",\n \"an.m.liebao.cn\",\n \"an.wikigifth.com\",\n \"an.yandex.ru\",\n \"ana.tatahn.com\",\n \"analy.qq.com\",\n \"andmejs.com\",\n \"android.push.126.net\",\n \"android.rqd.qq.com\",\n \"androidlog.shouji.baofeng.com\",\n \"android-lrcresource.wps.cn\",\n \"andrqd.play.aiseet.atianqi.com\",\n \"anfeng.com\",\n \"angsrvr.com\",\n \"anioscp.com\",\n \"ann5.net\",\n \"anquan.baidu.com\",\n \"anquan.org\",\n \"anreson.net\",\n \"antivirus.baidu.com\",\n \"anyangruisi.com\",\n \"anysdk.com\",\n \"aodongjiaosu.com\",\n \"aombjl099.com\",\n \"aoodoo.feng.com\",\n \"aoodoo.weiphone.com\",\n \"aos.wall.youmi.net\",\n \"aos-creative.prf.hn\",\n \"apas.aipai.com\",\n \"api.0.0.0.0.cn\",\n \"api.adv.ott.cibntv.net\",\n \"api.ahjinshu.com\",\n \"api.android.dianru.com\",\n \"api.anti.wauee.com\",\n \"api.appodeal.com\",\n \"api.apps.sina.cn\",\n \"api.bailingjiankang.com\",\n \"api.bs.zui.com\",\n \"api.cmt.mob.com\",\n \"api.coolguang.com\",\n \"api.dewmobile.net\",\n \"api.dianru.com\",\n \"api.doumob.com\",\n \"api.dreamfull.cn\",\n \"api.dsp.yhd.com\",\n \"api.exc.mob.com\",\n \"api.g1.junfull.com\",\n \"api.g2.junfull.com\",\n \"api.gi.igexin.com\",\n \"api.goulegu.com\",\n \"api.growingio.com\",\n \"api.iapps.ifeng.com\",\n \"api.iimedia.cn\",\n \"api.ijunhai.com\",\n \"api.itaoxiaoshuo.com\",\n \"api.joybj.com\",\n \"api.ketedata.com\",\n \"api.koudaikj.com\",\n \"api.leadbolt.net\",\n \"api.mobgi.com\",\n \"api.mobula.sdk.duapps.com\",\n \"api.moogos.com\",\n \"api.mp.uc.cn\",\n \"api.newad.ifeng.com\",\n \"api.newbelden.com\",\n \"api.open.uc.cn\",\n \"api.pingstart.com\",\n \"api.ppoi.org\",\n \"api.primecaster.net\",\n \"api.push.daoyoudao.com\",\n \"api.ra2.xlmc.sec.miui.com\",\n \"api.rees46.com\",\n \"api.rideraid.net\",\n \"api.share.mob.com\",\n \"api.shuzilm.cn\",\n \"api.similarweb.com\",\n \"api.tr.blismedia.com\",\n \"api.tw06.xlmc.sec.miui.com\",\n \"api.ujian.cc\",\n \"api.union.vip.com\",\n \"api.uniplayad.com\",\n \"api.userstyles.org\",\n \"api.viglink.com\",\n \"api.waptest.taobao.com\",\n \"api.whizzone.com\",\n \"api.xk.miui.com\",\n \"api.y.igexin.com\",\n \"api.youxiaoad.com\",\n \"api.zol.com\",\n \"api2.play.cn\",\n \"api-flow.flyme.cn\",\n \"api-game.meizu.com\",\n \"apihk.growingio.com\",\n \"api-push.meizu.com\",\n \"api-shoulei-ssl.xunlei.com\",\n \"apisoft.df0535.com\",\n \"apk.idate520.com\",\n \"apk.supfast.net\",\n \"apkdo.com\",\n \"apkinfo.voole.com\",\n \"apklog.cp11.ott.cibntv.net\",\n \"apnmedia.ask.com\",\n \"apns.ios.ijinshan.com\",\n \"apoll.m.taobao.com\",\n \"apollo.caixin.com\",\n \"app.3987.com\",\n \"app.9yyg.cn\",\n \"app.abc000.today\",\n \"app.acm.dzwww.com\",\n \"app.eduancm.com\",\n \"app.houyi.baofeng.net\",\n \"app.hytdsm.com\",\n \"app.ibaiducdn.com\",\n \"app.jgyee.com\",\n \"app.jiuzhilan.com\",\n \"app.juwang.com\",\n \"app.lz55.cn\",\n \"app.moji001.com\",\n \"app.starschina.com\",\n \"app.tanwan.com\",\n \"app.uu.cc\",\n \"app.waps.cn\",\n \"app.wapx.cn\",\n \"app.wumii.com\",\n \"app.xizi.com\",\n \"app.xyjqy.com\",\n \"app01.nodes.gslb.mi-idc.com\",\n \"app02.nodes.gslb.mi-idc.com\",\n \"appads.com\",\n \"appboy.com\",\n \"appc.baidu.com\",\n \"appcdn.wapx.cn\",\n \"appcdn.wapx.com\",\n \"appcpa.net\",\n \"appdriver.cn\",\n \"appdriver.com.cn\",\n \"appfh.com\",\n \"app-g.39.net\",\n \"appget.cn\",\n \"appgift.sinaapp.com\",\n \"appjiagu.com\",\n \"applifier.com\",\n \"applog.uc.cn\",\n \"applogios.uc.cn\",\n \"applovin.com\",\n \"applvn.com\",\n \"app-monitor.ele.me\",\n \"appnext.com\",\n \"appodealx.com\",\n \"apppic.yingyongbei.com\",\n \"apps.mobilityware.com\",\n \"apps.outfit7.com\",\n \"apps.supfast.net\",\n \"apps2.outfit7.com\",\n \"appsdk.tanv.com\",\n \"appservices.comcsoft.com\",\n \"appsflyer.com\",\n \"appspromote.wostore.cn\",\n \"appsrv1.madserving.com\",\n \"appsrv4.madserving.com\",\n \"appsupdate.sinaapp.com\",\n \"appsupport.stargame.com\",\n \"apptentive.com\",\n \"appuu.cn\",\n \"apt.qumi.com\",\n \"aqgyju.cn\",\n \"aqqgli3vle.bid\",\n \"aqw.quanliyouxi.cn\",\n \"ar.atwola.com\",\n \"ar1.atwola.com\",\n \"ar7.atwola.com\",\n \"ar9.atwola.com\",\n \"aralego.com\",\n \"ard.ihookup.com\",\n \"ard.sweetdiscreet.com\",\n \"ard.yahoo.co.jp\",\n \"ardmall.com\",\n \"arealx.com\",\n \"aries.mzres.com\",\n \"ark.cocounion.com\",\n \"ark.cp21.ott.cibntv.net\",\n \"art.theta.sogoucdn.com\",\n \"as.bjmama.net\",\n \"as.casalemedia.com\",\n \"as.inbox.com\",\n \"as.kejet.com\",\n \"as.kejet.net\",\n \"as.sinahk.net\",\n \"as.trklinklog.com\",\n \"as.yuewz.com\",\n \"asd.projectfreetv.so\",\n \"asearch.alicdn.com\",\n \"ashiping.com\",\n \"ashow.pcpop.com\",\n \"asia.marketo.com\",\n \"ask.gaykes.com\",\n \"assets.210189.com\",\n \"assets.2343sdxs.com\",\n \"assets.258pcf.com\",\n \"assets.258ydh.com\",\n \"assets.easou.com\",\n \"asv.nuggad.net\",\n \"aswgbzsw.xingtangshuo.com\",\n \"aswl.d3kdh34.pw\",\n \"aswl.dfs3e4.pw\",\n \"aswl.zjhim.com\",\n \"aswlx.cn\",\n \"at.atwola.com\",\n \"at.mct01.com\",\n \"at98.com\",\n \"atanx.alicdn.com\",\n \"atanx2.alicdn.com\",\n \"atas.io\",\n \"atcryp.com\",\n \"atdmt.com\",\n \"athena.wan.sogou.com\",\n \"atiws.aipai.com\",\n \"atm.punchbox.org\",\n \"atm.sina.com\",\n \"atm.yoyi.com.cn\",\n \"atomicblast.lol\",\n \"atplay.cn\",\n \"att.stargame.com\",\n \"attach.s8bbs.com\",\n \"au.youmi.net\",\n \"audience.network\",\n \"authedmine.com\",\n \"avn.innity.com\",\n \"avpa.dzone.com\",\n \"avualrhg9p.bid\",\n \"aw.kejet.net\",\n \"award.sitekeuring.net\",\n \"awempire.com\",\n \"awkjs.com\",\n \"awyys.com\",\n \"ax.120ask.com\",\n \"ax.ggfeng.com\",\n \"axhxa.com\",\n \"axiba66.com\",\n \"axkxy.com\",\n \"ayabreya.xyz\",\n \"b.53yao.com\",\n \"b.77vcd.com\",\n \"b.9dreams.net\",\n \"b.ads1.msn.com\",\n \"b.aowugame.com\",\n \"b.babylon.com\",\n \"b.baiy.net\",\n \"b.bst.126.net\",\n \"b.clkservice.youdao.com\",\n \"b.code.tanwanyx.com\",\n \"b.cyone.com.cn\",\n \"b.epinv.com\",\n \"b.flyreading.cn\",\n \"b.gwylm.com\",\n \"b.kuangtuiguoo18888.com\",\n \"b.livesport.eu\",\n \"b.localpages.com\",\n \"b.nvrentao8.com\",\n \"b.qchannel03.cn\",\n \"b.rifub.com\",\n \"b.scorecardresearch.com\",\n \"b.thefile.me\",\n \"b.xcafe.com\",\n \"b0.qinsx.cn\",\n \"b1.51scw.net\",\n \"b1.91jucai.com\",\n \"b1.c1km4.com\",\n \"b17.8794.cn\",\n \"b17.shangc.net\",\n \"b17.xiumu.cn\",\n \"b1sync.zemanta.com\",\n \"b4xuj.zzhhts.com\",\n \"b7nkd.cn\",\n \"b92.putniktravel.com\",\n \"b9377h.com\",\n \"b99u.top\",\n \"ba.ccm2.net\",\n \"ba.fqzds.com\",\n \"ba.kioskea.net\",\n \"baby.yf898.com\",\n \"backup.lumion3d.com\",\n \"backup.lumion3d.net\",\n \"bad1.51gxqm.com\",\n \"badad.googleplex.com\",\n \"badao37.net\",\n \"bai3.gushiwen.org\",\n \"baiapk.com\",\n \"baichuan.baidu.com\",\n \"baidu.cybcyw.com\",\n \"baidu.dsp.tansuotv.com\",\n \"baidu.greenxf.cn\",\n \"baidu.jz5u.net\",\n \"baiduace.com\",\n \"baidujs.cnys.com\",\n \"baidulao.com\",\n \"baidustatic.com\",\n \"baidut.github.io\",\n \"baidutv.baidu.com\",\n \"baidu-union-js.xiachufang.com\",\n \"baidu-union-pos.xiachufang.com\",\n \"baiduyubaidu.com\",\n \"baiduzhidahao.cc\",\n \"baifen.music.baidu.com\",\n \"baifendian.com\",\n \"baigm.com\",\n \"baiwanchuangyi.com\",\n \"bam.nr-data.net\",\n \"banlv.baidu.com\",\n \"banmamedia.com\",\n \"bannedbook.org\",\n \"banner.101xp.com\",\n \"banner.3ddownloads.com\",\n \"banner.automotiveworld.com\",\n \"banner.cooguo.com\",\n \"banner.europacasino.com\",\n \"banner.itweb.co.za\",\n \"banner.telefragged.com\",\n \"banner.titancasino.com\",\n \"banner1.pornhost.com\",\n \"banners.beevpn.com\",\n \"banners.beted.com\",\n \"banners.cams.com\",\n \"banners.clubworldgroup.com\",\n \"banners.expressindia.com\",\n \"banners.itweb.co.za\",\n \"banners.playocio.com\",\n \"bannershotlink.perfectgonzo.com\",\n \"baoyatu.cc\",\n \"bar.baidu.com\",\n \"bartender.cc\",\n \"base.filedot.xyz\",\n \"bat.bing.com\",\n \"bax.xiawu.com\",\n \"baxf.m.shuhuangge.org\",\n \"bay.xiawu.com\",\n \"baycode.cn\",\n \"bayimob.com\",\n \"bazinga.mse.sogou.com\",\n \"bb.tuku.cc\",\n \"bb1429.com\",\n \"bbcc.yxlady.com\",\n \"bbcoe.cn\",\n \"bbdm.051661.com\",\n \"bbsimages.zkxf119.com\",\n \"bc.geocities.yahoo.co.jp\",\n \"bccyyc.com\",\n \"bcjjg.bugsevent.com\",\n \"bcjxf.bugsevent.com\",\n \"bd.ershenghuo.com\",\n \"bd.gow100.com\",\n \"bd.haomagujia.com\",\n \"bd.soarfi.cn\",\n \"bd.wayqq.cn\",\n \"bd01.daqiso.com\",\n \"bd1.365qilu.com\",\n \"bd1.52che.com\",\n \"bd1.fengdu100.com\",\n \"bd1.flfgw.cn\",\n \"bd1.home8080.cn\",\n \"bd1.jobui.com\",\n \"bd1.nipic.com\",\n \"bd1.nxing.cn\",\n \"bd1.pipaw.com\",\n \"bd1.szhk.com\",\n \"bd1.wowoqq.com\",\n \"bd1.xiangha.com\",\n \"bd2.52che.com\",\n \"bd2.flfgw.cn\",\n \"bd2.home8080.cn\",\n \"bd2.jobui.com\",\n \"bd2.nipic.com\",\n \"bd2.pipaw.com\",\n \"bd3.chuiyue.com\",\n \"bd3.jobui.com\",\n \"bd4.chuiyue.com\",\n \"bdad.hao224.com\",\n \"bdcode.gaosan.com\",\n \"bdcode.youke.com\",\n \"bdd.hainan.net\",\n \"bddm.999d.com\",\n \"bdfpb1.8684.com\",\n \"bdfpb2.8684.com\",\n \"bdjiaoben.wmxa.cn\",\n \"bdjs.120askimages.com\",\n \"bdjs.6237237.com\",\n \"bdjs.99.com.cn\",\n \"bdjs.999d.com\",\n \"bd-js.baixing.net\",\n \"bdjs.faxingzhan.com\",\n \"bdjs.itechwall.com\",\n \"bdjs.ixiumei.com\",\n \"bdjs.jb51.net\",\n \"bdjs.kaixin100.com\",\n \"bdjs.laonanren.com\",\n \"bdjs.ylq.com\",\n \"bdjs1.ixiumei.com\",\n \"bdlm.120askimages.com\",\n \"bdlm1.hc360.com\",\n \"bdlncs1.familydoctor.com.cn\",\n \"bdmjs.xywy.com\",\n \"bdmm.xywy.com\",\n \"bdplus.baidu.com\",\n \"bdpuaw.com\",\n \"bd-s.baixing.net\",\n \"bds.hainan.net\",\n \"bds.soarfi.cn\",\n \"bdtongfei.cn\",\n \"bduserlog.eastmoney.com\",\n \"beacon.gtimg.com\",\n \"beacon.krxd.net\",\n \"beacon.sina.com.cn\",\n \"beacon.tingyun.com\",\n \"beacon-us-sjc1.rubiconproject.com\",\n \"beap.adss.yahoo.com\",\n \"beap-bc.yahoo.com\",\n \"bebelait.com\",\n \"becode.qiushibaike.com\",\n \"beeho.site\",\n \"beerto.cn\",\n \"beha.ksmobile.com\",\n \"behe.com\",\n \"beilamusi.com\",\n \"beintoo.com\",\n \"benshiw.net\",\n \"bepolite.eu\",\n \"bes-progfree.com\",\n \"bet36500050.com\",\n \"beta.vpon.com\",\n \"betsonsport.ru\",\n \"betterzip.net\",\n \"bewaycare.com\",\n \"beyondcompare.cc\",\n \"bfdcdn.com\",\n \"bglog.bitauto.com\",\n \"bgrndi.com\",\n \"bh.contextweb.com\",\n \"bhjac.azvub.cn\",\n \"bianxianmao.com\",\n \"biddingos.com\",\n \"biddingx.com\",\n \"bidvertiser.com\",\n \"bigbos.top\",\n \"bigboy.eurogamer.net\",\n \"billionfocus.com\",\n \"binaryage-leechgate.herokuapp.com\",\n \"bingdianhuanyuan.cn\",\n \"bingyinq.com\",\n \"biq.keefung-zs.com\",\n \"bite.theta.sogoucdn.com\",\n \"bitsumactivationserver.com\",\n \"bivitr.com\",\n \"bixia.fymm.cn\",\n \"biyibia.com\",\n \"biz.gexing.com\",\n \"biz.live.xunlei.com\",\n \"biz.vpon.com\",\n \"biz.weibo.com\",\n \"biz37.net\",\n \"bizanti.youwatch.org\",\n \"bj.imp.voiceads.cn\",\n \"bj14.9669.cn\",\n \"bjcathay.com\",\n \"bjcu.u3.ucweb.com\",\n \"bjedpt.com\",\n \"bjs.9669.cn\",\n \"bkdg.net\",\n \"bl.wavecdn.de\",\n \"bla.gtimg.com\",\n \"blaaaa12.googlecode.com\",\n \"blb.winasdaq.com\",\n \"bllbaby.cn\",\n \"blogad01.myweb.hinet.net\",\n \"blogad02.myweb.hinet.net\",\n \"bluekai.com\",\n \"bluhostedbanners.blucigs.com\",\n \"bmg.wnbfw.com\",\n \"bmp.ali213.net\",\n \"bmp1.ali213.net\",\n \"bmw2ep.paomifen.cn\",\n \"bnrs.ilm.ee\",\n \"boardx.huanqiu.com\",\n \"bob.crazyshit.com\",\n \"bobo.163.com\",\n \"bolt.jebe.renren.com\",\n \"borsendental.com\",\n \"bosiwangzi.cn\",\n \"box.anchorfree.net\",\n \"boxercrazy.org\",\n \"boxshows.com\",\n \"boyxu.cn\",\n \"bp.mobad.ijinshan.com\",\n \"br.blackfling.com\",\n \"br.fling.com\",\n \"br.realitykings.com\",\n \"brakefluid.website\",\n \"brand.sogou.com\",\n \"brandshow.58.com\",\n \"brcache.madthumbs.com\",\n \"breeze.olclient.baofeng.com\",\n \"breezily168.com\",\n \"brizads.com\",\n \"bro.flyme.cn\",\n \"bryonypie.com\",\n \"bs.5442.com\",\n \"bs.serving-sys.com\",\n \"bs14.9669.cn\",\n \"bsch.serving-sys.com\",\n \"bsdev.cn\",\n \"bshare.cn\",\n \"bshare.optimix.asia\",\n \"bsiet.husky.sogou.com\",\n \"bss.pandora.xiaomi.com\",\n \"bstatic.1kejian.com\",\n \"bstatic.diyifanwen.com\",\n \"bt.xitongmonitor.com\",\n \"bt641499.gotoip4.com\",\n \"bthergyuan.com\",\n \"btlaunch.baidu.com\",\n \"btn.onlylady.com\",\n \"btn.pchome.net\",\n \"btr.domywife.com\",\n \"btrace.qq.com\",\n \"bttrack.com\",\n \"btyou.com\",\n \"bu01.zybang.com\",\n \"bu02.zybang.com\",\n \"bu1.duba.com\",\n \"bu2.duba.com\",\n \"bugtags.com\",\n \"business.92wy.com\",\n \"business.inveno.com\",\n \"buyimg.bianxianmao.com\",\n \"buysellads.com\",\n \"buyu8001.com\",\n \"bwp.theinsider.com.com\",\n \"bx.optimix.asia\",\n \"bx01.optimix.asia\",\n \"bxgmb.com\",\n \"bxjpl.cn\",\n \"by.dm5.com\",\n \"by.mbai.cn\",\n \"by.tel.cdndm.com\",\n \"by8974.com\",\n \"bydonline.com\",\n \"bypbwm.cn\",\n \"c.0.0.0.0.cn\",\n \"c.28487.net\",\n \"c.35kds.com\",\n \"c.365yigou.cn\",\n \"c.45io.com\",\n \"c.51y5.net\",\n \"c.adbxb.cn\",\n \"c.anmeilai.net\",\n \"c.baidu.com\",\n \"c.betrad.com\",\n \"c.bigmir.net\",\n \"c.bing.com\",\n \"c.bxb.oupeng.com\",\n \"c.codeonclick.com\",\n \"c.cyhx98.com\",\n \"c.cyto-biotherapy.com\",\n \"c.danangmo.cn\",\n \"c.data.mob.com\",\n \"c.dokrmob.com\",\n \"c.dzytjqcc.com\",\n \"c.effectivemeasure.net\",\n \"c.f1zd.com\",\n \"c.gj.qq.com\",\n \"c.guangtui1999.com\",\n \"c.gzsanxiaomingshi.cn\",\n \"c.idasui.cn\",\n \"c.iogous.com\",\n \"c.k429fma.com\",\n \"c.kbf365.cn\",\n \"c.kl6636.net\",\n \"c.kuwo.cn\",\n \"c.lianwangtech.com\",\n \"c.live.com\",\n \"c.lucktui.com\",\n \"c.metrigo.com\",\n \"c.mightiger.net\",\n \"c.minisplat.cn\",\n \"c.mkmp365.com\",\n \"c.mnjkw.cn\",\n \"c.mobishu.com\",\n \"c.msn.com\",\n \"c.msn.com.cn\",\n \"c.netu.tv\",\n \"c.ningbojipiao.com\",\n \"c.ns8d.com\",\n \"c.okmgy.cn\",\n \"c.panqis.cn\",\n \"c.panqishu.com\",\n \"c.piliangzhuce.cn\",\n \"c.ptffw.net\",\n \"c.queene.cn\",\n \"c.rexuebi.com\",\n \"c.rscxwmj.cn\",\n \"c.shunlige.com\",\n \"c.silvinst.com\",\n \"c.sss1989.com\",\n \"c.sssgao999.com\",\n \"c.start280.com\",\n \"c.statcounter.com\",\n \"c.statstat888.com\",\n \"c.sy123888.com\",\n \"c.t98u8f.com\",\n \"c.tctyb.cn\",\n \"c.v4dwkcv.com\",\n \"c.vip97.net\",\n \"c.wechat.jx.cn\",\n \"c.wkanx.com\",\n \"c.wrating.com\",\n \"c.xianguonongchang.org\",\n \"c.xznykf.org\",\n \"c.ylist.cn\",\n \"c.ynlysg.com\",\n \"c.youdao.com\",\n \"c.zgnm.cc\",\n \"c.zlongad.com\",\n \"c.zmjuan.org\",\n \"c.zxyywdj.org\",\n \"c0.ifengimg.com\",\n \"c03.optimix.asia\",\n \"c0563.com\",\n \"c0594.com\",\n \"c0i8h8ac7e.bid\",\n \"c1.4qx.net\",\n \"c1.668559.com\",\n \"c1.ifengimg.com\",\n \"c1.keyrun.cn\",\n \"c1.lianwangtech.com\",\n \"c1.minisplat.cn\",\n \"c1.popads.net\",\n \"c1.statcounter.com\",\n \"c1.ulink.cc\",\n \"c1.wkanx.com\",\n \"c1.xcy8.com\",\n \"c16cp358.com\",\n \"c2.58toto.net\",\n \"c2.popads.net\",\n \"c2.statcounter.com\",\n \"c3.gostats.cn\",\n \"c3.moogos.com\",\n \"c6.bjdianyue.com\",\n \"c6.lnymd.com\",\n \"c77777777.com\",\n \"c8.wangdq.com\",\n \"c8b.jcdb88.com\",\n \"ca.5173car.com\",\n \"ca.w8.com.cn\",\n \"caamei.com\",\n \"cacaca.0571yy.com\",\n \"cacaca.sp96878.com\",\n \"cacafly.net\",\n \"cache.betweendigital.com\",\n \"cache.soloth.com\",\n \"cache.xw126.com\",\n \"cachead.com\",\n \"cachenotice.cp11.ott.cibntv.net\",\n \"cachesit.com\",\n \"cache-ssl.celtra.com\",\n \"cad.chosun.com\",\n \"c-adash.m.taobao.com\",\n \"cadvv.heraldm.com\",\n \"cadvv.koreaherald.com\",\n \"caiyifz.com\",\n \"cal.meizu.com\",\n \"caliyuna.cn\",\n \"calopenupdate.comm.miui.com\",\n \"cams.pornrabbit.com\",\n \"cangnews.com\",\n \"canvas.thenextweb.com\",\n \"caob5.info\",\n \"caolvch.com\",\n \"cap.cyberlink.com\",\n \"cap.touclick.com\",\n \"car.mobadme.jp\",\n \"carbonads.net\",\n \"cas.clickability.com\",\n \"cas.criteo.com\",\n \"casalemedia.com\",\n \"casee.cn\",\n \"cash.neweramediaworks.com\",\n \"cast.innity.com\",\n \"cast.ra.icast.cn\",\n \"cast-bid27-j.adtdp.com\",\n \"castplatform.com\",\n \"catalog.video.msn.com\",\n \"catch.gift\",\n \"cayanfang.com\",\n \"cb.baidu.com\",\n \"cb.h5.coffeedak.cn\",\n \"cbjs.baidu.com\",\n \"cbs.wondershare.com\",\n \"cc.0133hao.net\",\n \"cc.1515788.net\",\n \"cc.365yigou.cn\",\n \"cc.700ok.net\",\n \"cc.dace.hupu.com\",\n \"cc.idasui.cn\",\n \"cc.moquanad.com\",\n \"cc.piao.jianzhigg.com\",\n \"cc.st123.info\",\n \"cc.xtgreat.com\",\n \"cc.yac8.com\",\n \"cca.mob.com\",\n \"ccb.uncle-ad.com\",\n \"ccbaihehq.com\",\n \"cccrir.com\",\n \"ccr.yxdown.com\",\n \"cctyly.com\",\n \"cd.bendibao.com\",\n \"cdgxq.com\",\n \"cdhoc.piyaji.cn\",\n \"cdn.0i-i0.com\",\n \"cdn.5bong.com\",\n \"cdn.adsk2.co\",\n \"cdn.adstract.com\",\n \"cdn.aegins.com\",\n \"cdn.aiclicash.com\",\n \"cdn.app.kachapt.cn\",\n \"cdn.app.liuxingyul.cn\",\n \"cdn.at.atwola.com\",\n \"cdn.atwola.com\",\n \"cdn.cooguo.com\",\n \"cdn.districtm.io\",\n \"cdn.dragonstatic.com\",\n \"cdn.dsp.com\",\n \"cdn.earnify.com\",\n \"cdn.fastclick.net\",\n \"cdn.hivps.xyz\",\n \"cdn.hyperpromote.com\",\n \"cdn.iclicash.com\",\n \"cdn.img.kachapt.cn\",\n \"cdn.img.liuxingyul.cn\",\n \"cdn.innity.net\",\n \"cdn.jesgoo.com\",\n \"cdn.jiuzhilan.com\",\n \"cdn.jllstudio.com\",\n \"cdn.komentary.aol.com\",\n \"cdn.krxd.net\",\n \"cdn.lu.sogoucdn.com\",\n \"cdn.marketgid.com\",\n \"cdn.mdotm.com\",\n \"cdn.media.innity.net\",\n \"cdn.millennialmedia.com\",\n \"cdn.mingmingtehui.com\",\n \"cdn.moji.com\",\n \"cdn.moji002.com\",\n \"cdn.moogos.com\",\n \"cdn.ndapp.com\",\n \"cdn.newapi.com\",\n \"cdn.optaim.com\",\n \"cdn.outfit7.com\",\n \"cdn.popcash.net\",\n \"cdn.popmyads.com\",\n \"cdn.puata.info\",\n \"cdn.scdng.com\",\n \"cdn.sp.rizhao9.com\",\n \"cdn.tianmidian.com\",\n \"cdn.tinglian.com\",\n \"cdn.vamaker.com\",\n \"cdn.viglink.com\",\n \"cdn.xianliao.me\",\n \"cdn.zampda.net\",\n \"cdn0.mobmore.com\",\n \"cdn1.lbesec.com\",\n \"cdn1.res.nx5.com\",\n \"cdn1.res.uzham.com\",\n \"cdn1.srv.revdepo.com\",\n \"cdn2.moji002.com\",\n \"cdnads.com\",\n \"cdn-ads.oss-cn-shanghai.aliyuncs.com\",\n \"cdnas.hyperpromote.com\",\n \"cdn-gcs.outfit7.com\",\n \"cdnimg.liehu.ijinshan.com\",\n \"cdnis.hyperpromote.com\",\n \"cdnmaster.com\",\n \"cdnny.com\",\n \"cdnpa.hyperpromote.com\",\n \"cdn-rtb.sape.ru\",\n \"cdn-settings.segment.com\",\n \"cdntest.a8tiyu.com\",\n \"cds.51y5.net\",\n \"cdyqc.com\",\n \"ced.sascdn.com\",\n \"cee1.iteye.com\",\n \"cee2.iteye.com\",\n \"cerebral.typn.com\",\n \"cfdanet.com\",\n \"cferw.com\",\n \"cfg-md.gridsumdissector.com\",\n \"cfg-vd.gridsumdissector.com\",\n \"cgskqg.com\",\n \"chadegongxiao.com\",\n \"chance-ad.com\",\n \"chanet.com.cn\",\n \"changan.bama555.com\",\n \"changhehengqi.com\",\n \"channel.fanxing.kugou.com\",\n \"channeladvisor.com\",\n \"chaojilamei.cn\",\n \"chaoliangyun.com\",\n \"chartbeat.com\",\n \"chartboost.com\",\n \"chebse.com\",\n \"chemdraw.com\",\n \"chemdraw.com.cn\",\n \"chengadx.com\",\n \"chenggao.cn\",\n \"chengzhao95511.com\",\n \"chenwen7788.com\",\n \"chicken18.com\",\n \"chidir.com\",\n \"chinacsky.com\",\n \"chinaheh.com\",\n \"chinaliftoff.io\",\n \"chinauma.net\",\n \"chinaweichu.net\",\n \"chjxzk.1555110.cn\",\n \"chmae.com\",\n \"chnhty.com\",\n \"chuantu.biz\",\n \"chushoushijian.cn\",\n \"ci.csefaazc.net\",\n \"ciajingman.com\",\n \"cilidaquan.pw\",\n \"cindy17club.com\",\n \"cip6.czpush.com\",\n \"cishantao.com\",\n \"ciyitan.com\",\n \"cj.qidian.com\",\n \"cjhq.baidu.com\",\n \"cjmakeding.com\",\n \"cjmkt.com\",\n \"cjmooter.xcache.kinxcdn.com\",\n \"cjroq.bealge.sogou.com\",\n \"ck.houyi.baofeng.net\",\n \"ck.kejet.net\",\n \"cl.he9630.com\",\n \"cl.webterren.com\",\n \"cl.xzqxzs.com\",\n \"cl0.webterren.com\",\n \"cl2.webterren.com\",\n \"cl3.webterren.com\",\n \"cl4.webterren.com\",\n \"cl5.webterren.com\",\n \"clarity.abacast.com\",\n \"cleaner.baidu.com\",\n \"click1n.soufun.com\",\n \"clickadu.com\",\n \"click-cn.plista.com\",\n \"clicki.cn\",\n \"clicklog.moviebox.baofeng.net\",\n \"clickm.fang.com\",\n \"clickn.fang.com\",\n \"clicks.beap.bc.yahoo.com\",\n \"clicks.superpages.com\",\n \"clickstrip.6wav.es\",\n \"clicktracks.com\",\n \"clickzs.com\",\n \"client.88tours.com\",\n \"client.sidesearch.lycos.com\",\n \"client.stats.yinyuetai.com\",\n \"client.tenddata.com\",\n \"client-api.ele.me\",\n \"client-dmp.suishenyun.cn\",\n \"cliushow.com\",\n \"clk.dxpmedia.com\",\n \"clk.gentags.net\",\n \"clk.madserving.com\",\n \"clk.optaim.com\",\n \"clk.pdb.madserving.com\",\n \"clk.taptica.com\",\n \"clk.uunt.com\",\n \"clkads.com\",\n \"clkrev.com\",\n \"clkservice.mail.youdao.com\",\n \"clkservice.union.youdao.com\",\n \"clkservice.youdao.com\",\n \"clkservice2.dict.youdao.com\",\n \"cloud.codenow.cn\",\n \"cloud.rovio.com\",\n \"cloud.zyiis.net\",\n \"cloudad.asia\",\n \"cloudcdn.yousee.com\",\n \"cloudmobi.net\",\n \"cm.adgrx.com\",\n \"cm.baidu.com\",\n \"cm.ctnsnet.com\",\n \"cm.eyereturn.com\",\n \"cm.mct01.com\",\n \"cm.netseer.com\",\n \"cm.p4p.cn.yahoo.com\",\n \"cm8.lycos.com\",\n \"cmarket.kejet.net\",\n \"cmaxisolation.com\",\n \"cmcdl.cmcm.com\",\n \"cmcore.com\",\n \"cmm.xmfish.com\",\n \"cmp288.com\",\n \"cmpp.gentags.net\",\n \"cms.an.m.liebao.cn\",\n \"cms.quantserve.com\",\n \"cmsapi.wifi8.com\",\n \"cmshow.gtimg.cn\",\n \"cmslayue.com\",\n \"cn.pub.vpon.com\",\n \"cn.tatami-solutions.com\",\n \"cnbole.net\",\n \"cncy8.com\",\n \"cndjs-1251973891.coshk.myqcloud.com\",\n \"cnetdirectintl.com\",\n \"cnetwidget.creativemark.co.uk\",\n \"cnfanglei.com\",\n \"cnhbxx.com\",\n \"cnkok.com\",\n \"cnn.dyn.cnn.com\",\n \"cnnic.cn\",\n \"cnnic.net\",\n \"cnnic.net.cn\",\n \"cnpinzhuo.com\",\n \"cnscdj.com\",\n \"cnsjx.net\",\n \"cnxad.com\",\n \"cnxad.net\",\n \"cnzhqs.com\",\n \"cnzz.cn\",\n \"cnzz.com\",\n \"co.dtech.baofeng.com\",\n \"cocounion.com\",\n \"cod.southmoney.com\",\n \"code.3shangyou.com\",\n \"code.fastclick.net\",\n \"code.hajuwang.cn\",\n \"code.hot-mob.com\",\n \"code.kaixinjiehun.com\",\n \"code.kejet.com\",\n \"code.laojiayoufang.com\",\n \"code.ttpaper.com\",\n \"code.wantaico.com\",\n \"code11.onetad.com\",\n \"code12.onetad.com\",\n \"code1f.m.shushu8.com\",\n \"code1fa.m.shushu8.com\",\n \"code222.com\",\n \"code668.com\",\n \"codenow.cn\",\n \"codesoftchina.com\",\n \"coinblind.com\",\n \"coinerra.com\",\n \"coin-have.com\",\n \"coinhive.com\",\n \"coin-hive.com\",\n \"coinhive-manager.com\",\n \"coin-hive-proxy-ybydcnjgkl.now.sh\",\n \"coinminerz.com\",\n \"coinnebula.com\",\n \"col.hztags.net\",\n \"col.pagechoice.net\",\n \"collector.githubapp.com\",\n \"collector.viki.io\",\n \"collector.wasu.cn\",\n \"combine.urbanairship.com\",\n \"com-eonsun-owl.oss-cn-hangzhou.aliyuncs.com\",\n \"com-eonsun-owl-user.oss-cn-hangzhou.aliyuncs.com\",\n \"comesgo.com\",\n \"comet.yahoo.com\",\n \"conf.funshion.com\",\n \"conf.vidown.cn\",\n \"conf.xiniuz.com\",\n \"config.baofeng.net\",\n \"config.cocounion.com\",\n \"config.ioam.de\",\n \"config.kuyun.com\",\n \"config.mobisage.cn\",\n \"config.push.sogou.com\",\n \"config.unityads.unity3d.com\",\n \"config2.mparticle.com\",\n \"connect.summit.co.uk\",\n \"content.livesportmedia.eu\",\n \"content.s8bbs.com\",\n \"content.streamplay.to\",\n \"contentabc.com\",\n \"contentrecommend-out.mobile.sina.cn\",\n \"conv.youdao.com\",\n \"conversion.pro.cn\",\n \"conviva.com\",\n \"cooguo.com\",\n \"cookiemapping.wrating.com\",\n \"coolguang.com\",\n \"coolnay.com\",\n \"cooolyi.cn\",\n \"cooolyi.com\",\n \"coop.pop.baofeng.com\",\n \"cootek-dialer-download.oss-cn-hangzhou.aliyuncs.com\",\n \"cootek-file.cdn.cootekservice.com\",\n \"cop.my\",\n \"coreldrawchina.com\",\n \"coremetrics.com\",\n \"corner.houyi.baofeng.net\",\n \"coro.benbaisteel.com\",\n \"corocksi.com\",\n \"corp.meitu.com\",\n \"corp.sohu.com\",\n \"cosoyoo.com\",\n \"count.cpm.cm.kankan.com\",\n \"count.knowsky.com\",\n \"count.mail.163.com\",\n \"count.pcpop.com\",\n \"count.video.sina.com.cn\",\n \"count.wk2.com\",\n \"count5.pconline.com.cn\",\n \"count6.pconline.com.cn\",\n \"counter.csdn.net\",\n \"counter.kingsoft.com\",\n \"counter.m1905.com\",\n \"counter.marketgid.com\",\n \"counter.sina.com.cn\",\n \"counter.yadro.ru\",\n \"counter.yesky.com\",\n \"countpvn.light.fang.com\",\n \"countubn.light.soufun.com\",\n \"couqm.com.cn\",\n \"cp.5jjx.net\",\n \"cp.ggyapp.com\",\n \"cp.greenxf.cn\",\n \"cp.gs307.com\",\n \"cp.jfcdns.com\",\n \"cp.jz5u.net\",\n \"cpc.sogou.com\",\n \"cpc.sohu.com\",\n \"cpcv.cc\",\n \"cpm.amateurcommunity.com\",\n \"cpm.amateurcommunity.de\",\n \"cpm.cm.sandai.net\",\n \"cpmchina.co\",\n \"cpms.cc\",\n \"cpro.9xu.com\",\n \"cpro.baidu.cn\",\n \"cpro.baidu.com\",\n \"cpro.fangtoo.com\",\n \"cpro.zhidao.baidu.com\",\n \"cpro.zol.com.cn\",\n \"cpro1.edushi.com\",\n \"cpro2.baidu.com\",\n \"cps.360buy.com\",\n \"cpu-admin.baidu.com\",\n \"cpv.channelray\",\n \"cpv.czpush.com\",\n \"cpv.ty229.com\",\n \"cpv6.com\",\n \"cpva.cc\",\n \"cpv-adv.ggytc.com\",\n \"cpx24.com\",\n \"cqfangduan.com\",\n \"cqftonline.com\",\n \"cqhnm.com\",\n \"cqhot.club\",\n \"cqsta.com\",\n \"cqyhd.com\",\n \"cr.m.liebao.cn\",\n \"crashapi.growingio.com\",\n \"crashes.mo.wps.cn\",\n \"crasheye.cn\",\n \"crashlytics.163.com\",\n \"crashlytics.com\",\n \"crdrjs.info\",\n \"cre.dp.sina.cn\",\n \"cre.mix.sina.com.cn\",\n \"cre99.com\",\n \"creatim.qtmojo.cn\",\n \"creative.1111cpc.com\",\n \"creative.jdkic.com\",\n \"creative.ltheanine.cn\",\n \"creatives.cliphunter.com\",\n \"creatives.ftchinese.com\",\n \"creatives.inmotionhosting.com\",\n \"creatives.livejasmin.com\",\n \"creatives.pichunter.com\",\n \"creatives.summitconnect.co.uk\",\n \"creatives1.ftimg.net\",\n \"cre-dp.sina.cn\",\n \"criteo.com\",\n \"criteo.net\",\n \"crl.microsoft.com\",\n \"crm-eve.b2b.alibaba-inc.com\",\n \"cr-nielsen.com\",\n \"crosschannel.com\",\n \"crossoverchina.com\",\n \"cr-p16.ladsp.com\",\n \"crs.baidu.com\",\n \"crwdcntrl.net\",\n \"cs.dqwjzm.com\",\n \"cs.twcczhu.com\",\n \"csad.cc\",\n \"csbew.com\",\n \"csi.gstatic.com\",\n \"csqiulong.com\",\n \"cstoa.com\",\n \"csxjys.com\",\n \"cszlks.com\",\n \"ct.210189.com\",\n \"ct.niu.xunlei.com\",\n \"cti.w55c.net\",\n \"ctrmi.com\",\n \"ctsywy.com\",\n \"cudaojia.com\",\n \"cupid.jebe.renren.com\",\n \"current.sina.com.cn\",\n \"customad.cnn.com\",\n \"customer-security.online\",\n \"cut.qumi.com\",\n \"cvda.17173.com\",\n \"cvt.mydas.mobi\",\n \"cwpush.com\",\n \"cws-cctv.conviva.com\",\n \"cy123.cc\",\n \"cyacc.com\",\n \"cyad.cc\",\n \"cyad1.cyworld.com\",\n \"cyad1.nate.com\",\n \"cyad123.com\",\n \"cycy.kxrxh.com\",\n \"cylinderlongcheng.com\",\n \"cyylove.com\",\n \"cz.ifeng0.com\",\n \"cz01016102.cg2017.com\",\n \"cz01016102.ms758.com\",\n \"czdqhyo1.net\",\n \"czf.cchfjz.com\",\n \"czjiuding.cn\",\n \"czpush.com\",\n \"czpwm.com\",\n \"czxiangyue.com\",\n \"d.107788.com\",\n \"d.1391.com\",\n \"d.39.net\",\n \"d.admx.baixing.com\",\n \"d.agkn.com\",\n \"d.annarbor.com\",\n \"d.beigedi.com\",\n \"d.businessinsider.com\",\n \"d.clkservice.youdao.com\",\n \"d.danangmo.cn\",\n \"d.elong.cn\",\n \"d.gossipcenter.com\",\n \"d.kugou.com\",\n \"d.ligatus.com\",\n \"d.mingyihui.net\",\n \"d.rexuebi.com\",\n \"d.ruiwen.com\",\n \"d.thelocal.com\",\n \"d.tjgxzs.com\",\n \"d.tonghua5.com\",\n \"d.turn.com\",\n \"d.union.ijinshan.com\",\n \"d.xinshipu.com\",\n \"d.yjbys.com\",\n \"d.yoyi.com.cn\",\n \"d.yoyi.tv\",\n \"d0.sina.com.cn\",\n \"d0.sinaimg.cn\",\n \"d0.xcar.com.cn\",\n \"d00.sina.com.cn\",\n \"d1.showself.com\",\n \"d1.sina.com.cn\",\n \"d1.sinaimg.cn\",\n \"d1ad.com\",\n \"d1grtyyel8f1mh.cloudfront.net\",\n \"d1zgderxoe1a.cloudfront.net\",\n \"d2.sina.com.cn\",\n \"d2.sinaimg.cn\",\n \"d2.yiche.com\",\n \"d29qt51jeyi6xb.cloudfront.net\",\n \"d2qkpebv23oowx.cloudfront.net\",\n \"d3.sina.com.cn\",\n \"d3.sinaimg.cn\",\n \"d31qbv1cthcecs.cloudfront.net\",\n \"d36eyd5j1kt1m6.cloudfront.net\",\n \"d3f.houyi.baofeng.net\",\n \"d3g.qq.com\",\n \"d3v1lb83psg9di.cloudfront.net\",\n \"d4.sina.com.cn\",\n \"d5.sina.com.cn\",\n \"d520m.gzcl999.cn\",\n \"d5nxst8fruw4z.cloudfront.net\",\n \"d5p.de17a.com\",\n \"d6.sina.com.cn\",\n \"d6.sinaimg.cn\",\n \"d7.sina.com.cn\",\n \"d7.sinaimg.cn\",\n \"d77777777.com\",\n \"d8.sina.com.cn\",\n \"d8.sinaimg.cn\",\n \"d8.zedo.com\",\n \"d8360.com\",\n \"d8885.com\",\n \"d9.sina.com.cn\",\n \"daa.shuzilm.cn\",\n \"dacash.streamplay.to\",\n \"dadjia.com\",\n \"dads.new.digg.com\",\n \"dafahao.com\",\n \"dafahao.org\",\n \"dafapromo.com\",\n \"dahanedu.com\",\n \"dai.shuzilm.cn\",\n \"dailydeals.amarillo.com\",\n \"dailydeals.augustachronicle.com\",\n \"dailydeals.brainerddispatch.com\",\n \"dailydeals.lubbockonline.com\",\n \"dailydeals.onlineathens.com\",\n \"dailydeals.savannahnow.com\",\n \"dailylog.storm.baofeng.com\",\n \"dailyvideo.securejoin.com\",\n \"daima.23yy.com\",\n \"daima.chazidian.com\",\n \"daima.diaoben.net\",\n \"daima.dsxdn.com\",\n \"daima.huoche.net\",\n \"daima.ijq.tv\",\n \"daima.mubite.cn\",\n \"daima.youbian.com\",\n \"daima123.cc\",\n \"dairuqi.com\",\n \"daitdai.com\",\n \"dajean.com\",\n \"dajiyuan.com\",\n \"dajiyuan.org\",\n \"dalianhengtai.com\",\n \"dandan11.top\",\n \"dandan13.top\",\n \"dandan15.top\",\n \"danpinwu.com\",\n \"dante2007.com\",\n \"daohang.114so.cn\",\n \"daoyoudao.com\",\n \"dap.pagechoice.net\",\n \"dart.clearchannel.com\",\n \"dashet.com\",\n \"data.3975.com\",\n \"data.ad-score.com\",\n \"data.apn.co.nz\",\n \"data.danmu.baofeng.com\",\n \"data.doodlemobile.com\",\n \"data.gosquared.com\",\n \"data.mistat.xiaomi.com\",\n \"data.neuroxmedia.com\",\n \"data2.doodlemobile.com\",\n \"data2.gosquared.com\",\n \"databank.air.yoyi.com.cn\",\n \"databank.yoyi.com.cn\",\n \"datacapture.serving-sys.com\",\n \"datafastguru.info\",\n \"data-news.cdn.cootekservice.com\",\n \"data-pic.cdn.cootekservice.com\",\n \"datax.baidu.com\",\n \"datouniao.com\",\n \"dawwx.com\",\n \"day66.com\",\n \"dazhantai.com\",\n \"dazhonghua.cn\",\n \"db1.fuz.cc\",\n \"db2.fuz.cc\",\n \"dbam.dashbida.com\",\n \"dbncp.com\",\n \"dbregistration.cuteftp.com\",\n \"dbwmjj.com\",\n \"dc.cp21.ott.cibntv.net\",\n \"dc.csdn.net\",\n \"dc.liuliang100.com\",\n \"dc.meitustat.com\",\n \"dc.vmoters.com\",\n \"dc.xhct66.com\",\n \"dc2.csdn.net\",\n \"d-cache.microad-cn.com\",\n \"dcad.watersoul.com\",\n \"dcads.sina.com.cn\",\n \"dcapps.disney.go.com\",\n \"dcjs.cig.com.cn\",\n \"dcw.hdswgc.com\",\n \"dd.70yst.com\",\n \"dd.dante2007.com\",\n \"dd.iask.cn\",\n \"dd.iaskgo.com\",\n \"dd.mangofortune.net\",\n \"dd.wx16999.com\",\n \"ddanq.com\",\n \"ddapp.cn\",\n \"ddd.haodizhi666.com\",\n \"ddd.yuyouge.com\",\n \"ddg1277.com\",\n \"ddhtek.com\",\n \"ddkkrrla.m.qxs.la\",\n \"ddomm.com\",\n \"ddpxhq.cn\",\n \"ddrrccck.m.qxs.la\",\n \"de.as.cp61.ott.cibntv.net\",\n \"de.dzribao.com\",\n \"de.ioam.de\",\n \"de.pandora.xiaomi.com\",\n \"deals.ledgertranscript.com\",\n \"debugreport.mobiledissector.com\",\n \"dejing.laobanfa.com\",\n \"deletemer.online\",\n \"deliver.kuwo.cn\",\n \"delivery.maihehd.com\",\n \"delivery.playallvideos.com\",\n \"delivery.porn.com\",\n \"delivery.wasu.cn\",\n \"delivery-pc.wasu.cn\",\n \"demo.jointreport-switch.com\",\n \"desk.cmix.org\",\n \"detuns.com\",\n \"dev.tg.youxi.com\",\n \"devs.data.mob.com\",\n \"dezfu.com\",\n \"df3n43m.com\",\n \"df77.com\",\n \"dfad.dfdaily.com\",\n \"dfc1.benbaisteel.com\",\n \"dfp.suning.com\",\n \"dfx.shhuixiangwuliu.com\",\n \"dfx.vnnv777.cn\",\n \"dgfggy.com\",\n \"dgpzx.com\",\n \"dh.holaworld.cn\",\n \"dhxyzx.cn\",\n \"diag-vd.gridsumdissector.com\",\n \"diag-wd.gridsumdissector.com\",\n \"dialer.cdn.cootekservice.com\",\n \"dianjoy.com\",\n \"dianru.com\",\n \"diaojiaoji168.com\",\n \"diaopic.14bobo.com\",\n \"diediao.com\",\n \"difnxm.cn\",\n \"digdug.divxnetworks.com\",\n \"dimg1.sz.net.cn\",\n \"dingon.com.cn\",\n \"dip.pyangzi.com\",\n \"dip.szhyzkj.com\",\n \"dip.wl963.com\",\n \"dip.zgydjr.com\",\n \"dipan.com\",\n \"directrev.com\",\n \"dis.crieto.com\",\n \"dis.criteo.com\",\n \"dis.us.criteo.com\",\n \"discuz.gtimg.cn\",\n \"dispenser-rtb.sape.ru\",\n \"display.360totalsecurity.com\",\n \"display.ad.daum.net\",\n \"display.adhudong.com\",\n \"display.digitalriver.com\",\n \"display.superbay.net\",\n \"disqusads.com\",\n \"distf.kankan.com\",\n \"diyxjd.com\",\n \"djs.baomihua.com\",\n \"dkdlsj.com\",\n \"dkeyn.com\",\n \"dl.2345.com\",\n \"dl.360safe.com\",\n \"dl.9xu.com\",\n \"dl.client.baidu.com\",\n \"dl.cm.ksmobile.com\",\n \"dl.eduancm.com\",\n \"dl.img80.net\",\n \"dl.jianshunrui.com\",\n \"dl.kinbest.cn\",\n \"dl.kjava.sina.cn\",\n \"dl.mbsea.com\",\n \"dl.nx5.com\",\n \"dl.ops.baidu.com\",\n \"dl.sybspools.com\",\n \"dl.union.ijinshan.com\",\n \"dl.uu.cc\",\n \"dl.wan.sogoucdn.com\",\n \"dl.xzqxzs.com\",\n \"dl.youjia2016.com\",\n \"dl1sw.baidu.com\",\n \"dl2.bav.baidu.com\",\n \"dleke.com\",\n \"dlimg.lovfp.com\",\n \"dload.qd.qingting.fm\",\n \"dlpifu.com\",\n \"dlrijiaele.com\",\n \"dlsw.baidu.com\",\n \"dlsw.br.baidu.com\",\n \"dl-vip.bav.baidu.com\",\n \"dl-vip.pcfaster.baidu.co.th\",\n \"dlzjdesign.com\",\n \"dm.388g.cc\",\n \"dm.51okc.com\",\n \"dm.92to.com\",\n \"dm.aizhan.com\",\n \"dm.bytedance.com\",\n \"dm.chalook.net\",\n \"dm.fsyzcs.com\",\n \"dm.gbeik.com\",\n \"dm.jb51.net\",\n \"dm.jinshasi.cn\",\n \"dm.jsyst.cn\",\n \"dm.jy135.com\",\n \"dm.ppzuowen.com\",\n \"dm.pstatp.com\",\n \"dm.pw0.cn\",\n \"dm.riji.cn\",\n \"dm.sanwen.net\",\n \"dm.sanwen8.com\",\n \"dm.sb580.com\",\n \"dm.toutiao.com\",\n \"dm.ws8.org\",\n \"dm.yjbys.com\",\n \"dm1.tom61.com\",\n \"dm50.jkyd.net\",\n \"dm50.yxlady.com\",\n \"dmacore.kejet.com\",\n \"dmacore.kejet.net\",\n \"dmg.digitaltarget.ru\",\n \"dmp.kejet.net\",\n \"dmp.sina.cn\",\n \"dmpclick.deliver.ifeng.com\",\n \"dmrtb.com\",\n \"dmt.qcrx.cn\",\n \"dmtrck.com\",\n \"dn3.ixinwei.com\",\n \"dn7788.com\",\n \"dn-growing.qbox.me\",\n \"dnvus.com\",\n \"do.lymstsc.com\",\n \"do69ifsly4.me\",\n \"doc.go.sohu.com\",\n \"dol.deliver.ifeng.com\",\n \"dolphin.deliver.ifeng.com\",\n \"dolphin.ftimg.net\",\n \"dolphin4.ftimg.net\",\n \"doubleclick.net\",\n \"domed.shenbimall.com\",\n \"do-not-tracker.org\",\n \"dontblockme.modaco.com\",\n \"dopa.com\",\n \"dot.eporner.com\",\n \"dot2.eporner.com\",\n \"dotmore.com.tw\",\n \"dou777.com\",\n \"doubleplay-conf-yql.media.yahoo.com\",\n \"doubleverify.com\",\n \"doudao.cn\",\n \"doudouguo.com\",\n \"dougou88.com\",\n \"doumob.com\",\n \"down.360safe.com\",\n \"down.91wangmeng.com\",\n \"down.bugeyu.com\",\n \"down.dashendown.com\",\n \"down.diannaodian.com\",\n \"down.laomaotao.net\",\n \"down.winads.cn\",\n \"down.winbaicai.com\",\n \"down.xiazaidc.com\",\n \"down.xiazaiyuan.net\",\n \"downlaod.xiaocen.com\",\n \"download.123cw.cn\",\n \"download.2345.com\",\n \"download.350.com\",\n \"download.bav.baidu.com\",\n \"download.coolguang.com\",\n \"download.fuyuncc.com\",\n \"download.mediaget.com\",\n \"download.qianka.com\",\n \"download.sd.baidu.com\",\n \"download.sj.qq.com\",\n \"download.zhushou.sogou.com\",\n \"download3.123cw.cn\",\n \"downloada.dewmobile.net\",\n \"downloadb.dewmobile.net\",\n \"downmobile.kugou.com\",\n \"dp.559.cc\",\n \"dpm.demdex.net\",\n \"dps.499.cn\",\n \"dps.shouji56.com\",\n \"dps.wtdtjs.com\",\n \"dpvc.39.net\",\n \"dpvc1.qqyy.com\",\n \"dpvc2.qqyy.com\",\n \"dpvchos.qqyy.com\",\n \"dpvcimg.qqyy.com\",\n \"dqq.lnfund.org.cn\",\n \"dqsft.com\",\n \"dr.holaworld.cn\",\n \"dragoncent.com\",\n \"drd.hauchi.com.tw\",\n \"drdj.m.gxwztv.com\",\n \"drdwy.com\",\n \"dreamfull.cn\",\n \"dressimage.img-cn-beijing.aliyuncs.com\",\n \"drlsf.com\",\n \"drm.cmgame.com\",\n \"drmcmm.baidu.com\",\n \"drsw.m.yuyouge.com\",\n \"drvmy.ats68.cn\",\n \"drxrc.com\",\n \"ds.jlbksy.com\",\n \"ds.serving-sys.com\",\n \"dsadas.hydp188.com\",\n \"dsaeerf.com\",\n \"dshrx.com\",\n \"dsjsee.dqgpb.com\",\n \"ds-ll.serving-sys.com\",\n \"dsp.adfarm1.adition.com\",\n \"dsp.com\",\n \"dsp.hypers.com.cn\",\n \"dsp.pro.cn\",\n \"dsp.send.microad-cn.com\",\n \"dsp.simba.taobao.com\",\n \"dsp.toutiao.com\",\n \"dsp.youdao.com\",\n \"ds-pc.admsger.com\",\n \"dsp-click.youdao.com\",\n \"dsp-impr.youdao.com\",\n \"dsp-impr2.youdao.com\",\n \"dspmy.ge95.com\",\n \"dspserver.ad.cmvideo.cn\",\n \"ds-pv.iqu-operation.com\",\n \"dsxdn.com\",\n \"dt.adsafeprotected.com\",\n \"d-track.send.microad-cn.com\",\n \"dtrk.slimcdn.com\",\n \"dts.akamai.startappexchange.com\",\n \"duanat.com\",\n \"duapp.com\",\n \"duapps.com\",\n \"dugbvb.com\",\n \"dugesheying.com\",\n \"duiwai.baidu.com\",\n \"dumedia.ru\",\n \"duoyidd.com\",\n \"dushimj.com\",\n \"duusuu.com\",\n \"duyihu.net\",\n \"dv8c1t.cn\",\n \"dvb.pandora.xiaomi.com\",\n \"dvr8.com\",\n \"dvs.china.com\",\n \"dvsend.china.com\",\n \"dvser.china.com\",\n \"dvser02.china.com\",\n \"dvx-android.0.0.0.0.cn\",\n \"dw.koudaibl.com\",\n \"dw.xcar.com.cn\",\n \"dw998.com\",\n \"dwa.okwan.cn\",\n \"dx1200.com\",\n \"dxp.baidu.com\",\n \"dxpmedia.com\",\n \"dxprla.m.qxs.la\",\n \"dxssiyi.com\",\n \"dyb.jdcbuy.com\",\n \"dydab.com\",\n \"dyn.tnaflix.com\",\n \"dynamic.aol.com\",\n \"dynamic.zol.com.cn\",\n \"dz2017.zdzxyplyt.com\",\n \"dzais.com\",\n \"dzisou.com\",\n \"dzjzg.com\",\n \"dzl.baidu.com\",\n \"dzz.wankeedu.com\",\n \"e.0.0.0.0.cn\",\n \"e.0.0.0.0.com.cn\",\n \"e.027blzs.com\",\n \"e.0531mnk.net\",\n \"e.1919388.net\",\n \"e.28487.net\",\n \"e.51xmgys.com\",\n \"e.91.com\",\n \"e.aa985.cn\",\n \"e.acaog.com\",\n \"e.acaox.com\",\n \"e.admin60.com\",\n \"e.afvfe.cn\",\n \"e.anmeilai.net\",\n \"e.apxyz.com\",\n \"e.baidu.com\",\n \"e.bapkt.com\",\n \"e.bbvjs.com\",\n \"e.bentengcn.com\",\n \"e.bokanedu.net\",\n \"e.bsnnk.com\",\n \"e.bvoer.com\",\n \"e.cbeif.com\",\n \"e.ccunf.com\",\n \"e.cdfzcz.com\",\n \"e.chfuw.com\",\n \"e.cjieh.com\",\n \"e.ckikq.com\",\n \"e.cn-3drp.com\",\n \"e.codlw.com\",\n \"e.coenr.com\",\n \"e.crashlytics.com\",\n \"e.cuomm.com\",\n \"e.czggcj.com\",\n \"e.daishuxy.com\",\n \"e.danrs.com\",\n \"e.deimm.com\",\n \"e.diogv.com\",\n \"e.diupp.com\",\n \"e.dnfeu.com\",\n \"e.dsjre.com\",\n \"e.dunmm.com\",\n \"e.dxmci.com\",\n \"e.dzairen.com\",\n \"e.e7001.com\",\n \"e.e70123.com\",\n \"e.ehxyz.com\",\n \"e.emgwq.com\",\n \"e.enjuk.com\",\n \"e.ennmt.com\",\n \"e.fbaix.com\",\n \"e.fbaot.com\",\n \"e.fimky.com\",\n \"e.fkkse.com\",\n \"e.fkogs.com\",\n \"e.focuscat.com\",\n \"e.fstaw.com\",\n \"e.fwjoi.com\",\n \"e.fzyda.com\",\n \"e.gbieg.com\",\n \"e.gglay.com\",\n \"e.gxjfh.com\",\n \"e.gxkyl.com\",\n \"e.harbinbaojia.net\",\n \"e.hellomingpian.com\",\n \"e.hgrqp.com\",\n \"e.hissq.com\",\n \"e.hjryl.com\",\n \"e.hk7799.net\",\n \"e.hkmqp.com\",\n \"e.hmhqp.com\",\n \"e.hogyp.com\",\n \"e.hpzyl.com\",\n \"e.htper.com\",\n \"e.huaas.com\",\n \"e.hunpp.com\",\n \"e.huoas.com\",\n \"e.hurnt.com\",\n \"e.hyzui.com\",\n \"e.icyrd.com\",\n \"e.iierq.com\",\n \"e.infvb.com\",\n \"e.irauz.com\",\n \"e.irkuj.com\",\n \"e.iruad.com\",\n \"e.ishowms.com\",\n \"e.jdaot.com\",\n \"e.jgkto.com\",\n \"e.jiaas.com\",\n \"e.jiirz.com\",\n \"e.jioeg.com\",\n \"e.jkert.com\",\n \"e.jlkja.com\",\n \"e.jltdbyq.com\",\n \"e.jnsdkjzs.com\",\n \"e.joyxv.com\",\n \"e.juyzr.com\",\n \"e.jwiyr.com\",\n \"e.jxxiangchu.com\",\n \"e.kcooy.com\",\n \"e.kewro.com\",\n \"e.khuoy.com\",\n \"e.kjfhe.com\",\n \"e.kjhfy.com\",\n \"e.kl6636.net\",\n \"e.ksttwz.com\",\n \"e.kunpp.com\",\n \"e.kwjkd.com\",\n \"e.kxhie.com\",\n \"e.lancedu.com\",\n \"e.lfdydk.com\",\n \"e.lovezhishou.com\",\n \"e.lyjz001.com\",\n \"e.lzytt.com\",\n \"e.md0z4dh.com\",\n \"e.meizhuanghe.com\",\n \"e.miaoxinqipei.com\",\n \"e.mightiger.net\",\n \"e.miiuv.com\",\n \"e.mmkvi.com\",\n \"e.mozist.com\",\n \"e.mqgpo.com\",\n \"e.mrsasharingspace.com\",\n \"e.mrtuo.com\",\n \"e.mushizhubao.com\",\n \"e.nduop.com\",\n \"e.neijh.com\",\n \"e.nejup.com\",\n \"e.nernv.com\",\n \"e.nexac.com\",\n \"e.nfkos.com\",\n \"e.nmtouzi.com\",\n \"e.nnfiy.com\",\n \"e.nwxzs.com\",\n \"e.nxypz.com\",\n \"e.oesnw.com\",\n \"e.okfhn.com\",\n \"e.opqsr.com\",\n \"e.oyrim.com\",\n \"e.pbino.com\",\n \"e.picbr.com\",\n \"e.plerv.com\",\n \"e.pomkl.com\",\n \"e.poonscn.com\",\n \"e.pubbirdf.com\",\n \"e.puooi.com\",\n \"e.pwjhg.com\",\n \"e.pyerc.com\",\n \"e.qiaoyuwang.com\",\n \"e.qingzhencai.net\",\n \"e.qiyunmuye.com\",\n \"e.qsove.com\",\n \"e.qvxyz.com\",\n \"e.qxfly.com\",\n \"e.resmv.com\",\n \"e.ricpt.com\",\n \"e.rmwdn.com\",\n \"e.romgv.com\",\n \"e.sanitwealth.com\",\n \"e.shenyunkeji.com\",\n \"e.sjuqc.com\",\n \"e.sosjyx.com\",\n \"e.srrux.com\",\n \"e.suehy.com\",\n \"e.szqifu.com\",\n \"e.t71q.com\",\n \"e.tdtsd.com\",\n \"e.tiantianedu.net\",\n \"e.tick0.com\",\n \"e.tiojk.com\",\n \"e.tuoaa.com\",\n \"e.ueram.com\",\n \"e.uissm.com\",\n \"e.v02u9.cn\",\n \"e.vaxyz.com\",\n \"e.vbaiu.com\",\n \"e.vouky.com\",\n \"e.vvocm.com\",\n \"e.wcjup.com\",\n \"e.weixingshexiangji.net\",\n \"e.wikigifth.com\",\n \"e.wjhehaofc.com\",\n \"e.wkjhd.com\",\n \"e.wnxcg.com\",\n \"e.wonwg.com\",\n \"e.wsxxu.com\",\n \"e.x.cn.xtgreat.com\",\n \"e.xdkje.com\",\n \"e.xeihy.com\",\n \"e.xetvb.com\",\n \"e.xiangchim0.com\",\n \"e.xikdn.com\",\n \"e.xkqpco.com.com\",\n \"e.xlsschina15.net\",\n \"e.xmgysweb.com\",\n \"e.xpjis.com\",\n \"e.xxkio.com\",\n \"e.yageben.com\",\n \"e.yangjingbang.net\",\n \"e.yerpt.com\",\n \"e.yicang8.com\",\n \"e.yidulive.net\",\n \"e.yingchengtou.com\",\n \"e.ynnke.com\",\n \"e.yoiur.com\",\n \"e.youweiprint.com\",\n \"e.ysdangan.com\",\n \"e.ysdhe.com\",\n \"e.yuxyz.com\",\n \"e.ywbwsm.com\",\n \"e.yycqc.com\",\n \"e.yyeks.com\",\n \"e.yyjhf.com\",\n \"e.zabxb.com\",\n \"e.zhuyuanp.club\",\n \"e.zhuyuanp.shop\",\n \"e.zhuyuanp.top\",\n \"e.zjkdaikuan.com\",\n \"e.zkwsdf.com\",\n \"e.zunss.com\",\n \"e7001.com\",\n \"e7002.com\",\n \"e7009.com\",\n \"e701.net\",\n \"e70123.com\",\n \"e7015.com\",\n \"e704.net\",\n \"e705.net\",\n \"e706.net\",\n \"e708.net\",\n \"e719.net\",\n \"e9377f.com\",\n \"eacash.streamplay.to\",\n \"eap.big5.enorth.com.cn\",\n \"eap.enorth.com.cn\",\n \"easyrecoverychina.com\",\n \"ebook.res.meizu.com\",\n \"ebp.renren.com\",\n \"ec.kejet.net\",\n \"eclick.120ask.com\",\n \"eclick.360doc.com\",\n \"eclick.baidu.com\",\n \"eclkspbn.com\",\n \"ecma.bdimg.com\",\n \"ecmb.bdimg.com\",\n \"ecmc.bdimg.com\",\n \"ecuc123.net\",\n \"ed.aijielang.cn\",\n \"ed.sczhilong.cn\",\n \"eddong.com\",\n \"edesf.xyzxmark.cn\",\n \"edge.quantserve.com\",\n \"edge.sharethis.com\",\n \"edge.yunjiasu.com\",\n \"edigitalsurvey.com\",\n \"ediuschina.com\",\n \"edncui.net\",\n \"eduancm.com\",\n \"eduzzjy.com\",\n \"ee4kdushuba.com\",\n \"eee.eh39.co\",\n \"eee.kj78.org\",\n \"eee.ttyy888.co\",\n \"eeee500.com\",\n \"eezdx.erc.18183.com\",\n \"eff.inte.sogou.com\",\n \"effectivemeasure.com\",\n \"effectivemeasure.net\",\n \"ehd.baike.com\",\n \"ehxyz.com\",\n \"ein.51yingfa.com\",\n \"eiv.baidu.com\",\n \"ejzr.golden1.sogou.com\",\n \"ekeide.com\",\n \"eland.doublemax.net\",\n \"em.baidu.com\",\n \"emarbox.com\",\n \"emss.zjhim.com\",\n \"en.shenyun.com\",\n \"en.shenyun.org\",\n \"engine.lvehaisen.com\",\n \"engine.tuia.cn\",\n \"ent1.12584.cn\",\n \"entry.baidu.com\",\n \"e-p4p.163.com\",\n \"epernn.cn\",\n \"epochtimes.org\",\n \"epochweekly.com\",\n \"epowernetworktrackerimages.s3.amazonaws.com\",\n \"er.dlhygj.com\",\n \"erdoscs.com\",\n \"erebor.douban.com\",\n \"ereg.adobe.com\",\n \"ereg.wip3.adobe.com\",\n \"ers.baidu.com\",\n \"erwqw.zh1155.com\",\n \"erwr.ydjskvpd.com\",\n \"espn-ak.starwave.com\",\n \"esptj.com\",\n \"esrpxyahzna.bid\",\n \"eteun.cn\",\n \"ethod.gzgmjcx.com\",\n \"etl.xlmc.sandai.net\",\n \"etl.xlmc.sec.miui.com\",\n \"eu-gmtdmp.gd1.mookie1.com\",\n \"eum-appdynamics.com\",\n \"eus.rubiconproject.com\",\n \"euwidget.imshopping.com\",\n \"eva.ucas.com\",\n \"evefashion.cn\",\n \"event.ksosoft.com\",\n \"eventlog.hd.baofeng.com\",\n \"events.kalooga.com\",\n \"events.pingan.com\",\n \"events-api.outfit7.net\",\n \"eviltracker.net\",\n \"ew16d.package12.com\",\n \"ex.mobmore.com\",\n \"ex.puata.info\",\n \"exdynsrv.com\",\n \"exit.macandbumble.com\",\n \"exoclick.com\",\n \"exp.17wo.cn\",\n \"exp.3g.ifeng.com\",\n \"exp.qumi.com\",\n \"expo123.net\",\n \"ext.theglobalweb.com\",\n \"extmoney.i1608.com\",\n \"extstat.com\",\n \"eyd77s.com\",\n \"eye.swfchan.com\",\n \"eyouv.cn\",\n \"ez33.org.cn\",\n \"ezine.oupeng.com\",\n \"ezucods.cn\",\n \"f.520tingshu.com\",\n \"f.doodlemobile.com\",\n \"f.f70123.com\",\n \"f.fj95560.com\",\n \"f.haoxinjaju.com\",\n \"f.hongm.com\",\n \"f.qcwzx.net.cn\",\n \"f.yijikm.com\",\n \"f.yueyetiyu.com\",\n \"f1.06ps.com\",\n \"f1.bizhiku.net\",\n \"f1.luoshenbest.cn\",\n \"f1.meishichina.com\",\n \"f1.p0y.cn\",\n \"f1.pig66.com\",\n \"f1190.com\",\n \"f1c.i.biquge5200.com\",\n \"f2.p0y.cn\",\n \"f2zd.com\",\n \"f3.mi-stat.gslb.mi-idc.com\",\n \"f3.vedeh.com\",\n \"f5.dfcwg.com\",\n \"f5.mtqys.com\",\n \"f56g.me\",\n \"f6ce.com\",\n \"f70123.com\",\n \"f8272.com\",\n \"fa.163.com\",\n \"facebookma.cn\",\n \"faggrim.com\",\n \"fair.sogou.com\",\n \"falundata.com\",\n \"falundata.org\",\n \"fan.liuxiaoer.com\",\n \"fan.twitch.tv\",\n \"fancyapi.com\",\n \"fanqianbb.com\",\n \"fans.bestvogue.com\",\n \"fansi365.com\",\n \"fan-yong.com\",\n \"farm-cn.plista.com\",\n \"fastable.com\",\n \"fastapi.net\",\n \"fastcache.com.cn\",\n \"fast-cdn.dianjoy.com\",\n \"fastclick.com\",\n \"fastclick.net\",\n \"fastly.bench.cedexis.com\",\n \"fastpopunder.com\",\n \"fathionmall.com\",\n \"fav.simba.taobao.com\",\n \"fb.xk.miui.com\",\n \"fbc.ffychb.com\",\n \"fccxgjg.com\",\n \"fc-feed.cdn.bcebos.com\",\n \"fclick.baidu.com\",\n \"fcsass.org.cn\",\n \"fd.anzhi.com\",\n \"fd.qchannel03.cn\",\n \"fd7c.com\",\n \"fds.api.moji.com\",\n \"fe.lea.lycos.co.uk\",\n \"fe1-au.imrworldwide.com\",\n \"fe2-au.imrworldwide.com\",\n \"fe3-au.imrworldwide.com\",\n \"fe-au.imrworldwide.com\",\n \"feed.baidu.com\",\n \"feed.theta.sogou.com\",\n \"feedback.whalecloud.com\",\n \"feeds.logicbuy.com\",\n \"feeds.videosz.com\",\n \"fei232.bhzje7ua9.com\",\n \"feidalu.com\",\n \"feifish66.com\",\n \"feih.com.cn\",\n \"feitianma.com\",\n \"feixin2.com\",\n \"fembsflungod.com\",\n \"fen.dkdlsj.com\",\n \"fengbuy.com\",\n \"fenggejiaju.com\",\n \"fenqihome.com\",\n \"fenvm.com\",\n \"fexclick.baidu.com\",\n \"ff.nsg.org.ua\",\n \"ffb.feihuo.com\",\n \"fff.yuyouge.com\",\n \"ffhtek.com\",\n \"fflsn.com\",\n \"ffre.ffrepair.com\",\n \"ffychb.com\",\n \"fge9vbrzwt.bid\",\n \"fghm.ga25.com\",\n \"fghmc.ga25.com\",\n \"fghmimg.ga25.com\",\n \"fgmtv.org\",\n \"file.bmob.cn\",\n \"files2.sogou.com\",\n \"fimserve.ign.com\",\n \"findicons.com\",\n \"finding.hardwareheaven.com\",\n \"findnsave.idahostatesman.com\",\n \"finead.cn\",\n \"fips.uimserv.net\",\n \"firefang.cn\",\n \"fjkst.com\",\n \"fjlqqc.com\",\n \"fjmeyer.com\",\n \"fkku194.com\",\n \"flash.2144.com\",\n \"flashtalking.com\",\n \"flowcodeapp.com\",\n \"flstudiochina.com\",\n \"flurry.cachefly.net\",\n \"flurry.com\",\n \"flux.faloo.com\",\n \"flv.dotmore.com.tw\",\n \"flv.ytshuirun.com\",\n \"flwja.com\",\n \"fm.p0y.cn\",\n \"fmgoal.com\",\n \"fnkjj.com\",\n \"focuscat.com\",\n \"focusprolight.com\",\n \"formysql.com\",\n \"fota4.adups.cn\",\n \"fotao9.com\",\n \"founseezb.cn\",\n \"fozhu.rrsdl.com\",\n \"fp.fraudmetrix.cn\",\n \"fpb.51edu.com\",\n \"fpb.kuhou.com\",\n \"fpb.mn586.com\",\n \"fpbbdx1.51240.com\",\n \"fpbjiansuo.mn586.com\",\n \"fpdownload.macromedia.com\",\n \"fptest.fraudmetrix.cn\",\n \"fqtra.com\",\n \"frame.enet.com.cn\",\n \"fraudmetrix.cn\",\n \"frdhq.cn\",\n \"free.aol.com\",\n \"freecodecs.us.intellitxt.com\",\n \"freedrive.cn\",\n \"freexxxvideoclip.aebn.net\",\n \"fs.uc.nearme.com.cn\",\n \"fsjsp.com\",\n \"fsr.lenovomm.com\",\n \"fst360.com\",\n \"fs-uc-nearme-com-cn.oss-cn-hangzhou.aliyuncs.com\",\n \"fsyzcs.com\",\n \"ft.moad.cn\",\n \"ft.pnop.com\",\n \"fthcz.com\",\n \"fu68.com\",\n \"fucnm.com\",\n \"fujianryt.com\",\n \"fun.ynet.com\",\n \"funshion.net.cn\",\n \"fus.lenovomm.com\",\n \"fusion.qq.com\",\n \"fv99.com\",\n \"fw.adsafeprotected.com\",\n \"fw.vpon.com\",\n \"fwmrm.net\",\n \"fwt0.com\",\n \"fxc.aiquxs.com\",\n \"fxmacd.com\",\n \"fxtducb.cn\",\n \"fxxgw.com\",\n \"fych.uranus.sogou.com\",\n \"fydgold132.com\",\n \"fytza.cn\",\n \"fz863.com\",\n \"fzz.cloud.1234507.com\",\n \"fzz.shgqjr.com\",\n \"g.163.com\",\n \"g.51network.com\",\n \"g.6sfg.com\",\n \"g.ad8.cc\",\n \"g.aligames.com\",\n \"g.baidu.com\",\n \"g.bitauto.com\",\n \"g.brothersoft.com\",\n \"g.chuiyao.com\",\n \"g.d.yoyi.tv\",\n \"g.daman.cc\",\n \"g.f11w.com\",\n \"g.f5gh.com\",\n \"g.gridsum.com\",\n \"g.haluoha.com\",\n \"g.hsw.cn\",\n \"g.koowo.com\",\n \"g.mnw.cn\",\n \"g.ousns.net\",\n \"g.rs.yoyi.com.cn\",\n \"g.s8dj.com\",\n \"g.szdn1ms.com\",\n \"g.usingde.com\",\n \"g.w5b454.com\",\n \"g.wan.2345.com\",\n \"g.wan.douyu.com\",\n \"g.wrating.com\",\n \"g.x.cn.xtgreat.com\",\n \"g.x.evolife.cn\",\n \"g.yccdn.com\",\n \"g.zx-jsp.com\",\n \"g1.0573ren.com\",\n \"g1.08160.cn\",\n \"g1.163.com\",\n \"g1.taijuba.com\",\n \"g1c5.com\",\n \"g1f5.com\",\n \"g2.ousns.net\",\n \"g3.iqilu.com\",\n \"g4.iqilu.com\",\n \"g9s.sgzs999.com\",\n \"gad.kugou.com\",\n \"gadwhy.com\",\n \"gafxa.code.mytanwan.com\",\n \"galaxy.sogoucdn.com\",\n \"game.9xzj.com\",\n \"game.baichuanhd.cn\",\n \"game.html5.qq.com\",\n \"game.kugou.com\",\n \"game.kuwo.cn\",\n \"game.qidian.com\",\n \"game.res.meizu.com\",\n \"game.rising.cn\",\n \"game.subway.uu.cc\",\n \"game.weibo.cn\",\n \"game.weibo.com\",\n \"gamead.swjoy.com\",\n \"gameads.digyourowngrave.com\",\n \"gamebox.kugou.com\",\n \"game-res.meizu.com\",\n \"ganjituiguang.ganji.com\",\n \"gao.ynet.com\",\n \"gas.data.pplive.com\",\n \"gateway.fortunelounge.com\",\n \"gateways.s3.amazonaws.com\",\n \"gb.corp.163.com\",\n \"gc.keefung-zs.com\",\n \"gcapi.sy.kugou.com\",\n \"gclick.cn\",\n \"gcs1.cn\",\n \"gd.cnhange.cn\",\n \"gd.jqgc.com\",\n \"gd.vodtw.com\",\n \"gdbly.com\",\n \"gdgy56.com\",\n \"gdskywings.com\",\n \"gdsqwy.org\",\n \"gdyn.cnn.com\",\n \"ge95.com\",\n \"geili.co\",\n \"geiyujieda.com\",\n \"gemini.yahoo.com\",\n \"gen.alicdn.com\",\n \"gentags.com\",\n \"geo.cliphunter.com\",\n \"geo.connexionsecure.com\",\n \"geo.frtya.com\",\n \"geo.frtyd.com\",\n \"geo.gridsumdissector.com\",\n \"geo.moatads.com\",\n \"geo.yahoo.com\",\n \"geo2.adobe.com\",\n \"geobanner.alt.com\",\n \"geobanner.friendfinder.com\",\n \"geobanner.passion.com\",\n \"geobanner.socialflirt.com\",\n \"geoshopping.nzherald.co.nz\",\n \"geryi.com\",\n \"get.thefile.me\",\n \"get3.adobe.com\",\n \"getnormalizedurl.com\",\n \"gewuwen.com\",\n \"gf108.com\",\n \"gf1352.com\",\n \"gfd80.com\",\n \"gfh.ahfzly.com\",\n \"gfx.infomine.com\",\n \"gg.0598yu.com\",\n \"gg.5173.com\",\n \"gg.51cto.com\",\n \"gg.amblrgg.live\",\n \"gg.anqu.com\",\n \"gg.blueidea.com\",\n \"gg.caixin.com\",\n \"gg.cs090.com\",\n \"gg.dsxdn.com\",\n \"gg.gao7.com\",\n \"gg.haianw.com\",\n \"gg.huangye88.com\",\n \"gg.jkmeishi.com\",\n \"gg.kugou.com\",\n \"gg.meitu.com\",\n \"gg.ptfish.com\",\n \"gg.sonhoo.com\",\n \"gg.stargame.com\",\n \"gg.uuu9.com\",\n \"gg.vidown.cn\",\n \"gg.xywy.com\",\n \"gg.yxdown.com\",\n \"gg.zhongyao1.com\",\n \"gg0376.com\",\n \"gg1.yszyz.com\",\n \"gg2.51cto.com\",\n \"gg2.dss9927.com\",\n \"gg3.51cto.com\",\n \"gg570.com\",\n \"gg86.pinggu.org\",\n \"gg8888.cnfol.com\",\n \"ggb.douguo.com\",\n \"ggcode.2345.com\",\n \"ggdoubi.com\",\n \"ggg.zj.com\",\n \"ggle.lywf.me\",\n \"ggmm777.com\",\n \"ggmmqq.com\",\n \"ggr.yxdown.com\",\n \"ggs.myzaker.com\",\n \"ggw.gusuwang.com\",\n \"ggw.watertu.com\",\n \"ggxt.net\",\n \"gi.xi.gxabj.com\",\n \"gif.lu.sogoucdn.com\",\n \"gimg.baidu.com\",\n \"gimg.bitauto.com\",\n \"girlcc.cc\",\n \"gj500.com\",\n \"gjghy.com\",\n \"gjreg.code.weddingeeos.com\",\n \"glasszz.com\",\n \"gload.adhood.com\",\n \"global.msads.net\",\n \"global.ymtracking.com\",\n \"gm682.com\",\n \"gma1.com\",\n \"gmota.g188.net\",\n \"gmtdmp.mookie1.com\",\n \"go.gogolm.xyz\",\n \"go.gotourl.xyz\",\n \"go.gotourls.bid\",\n \"go.hangzhou.com.cn\",\n \"go.onclasrv.com\",\n \"go.util.zlibs.com\",\n \"godloveme.cn\",\n \"gog9.qzdfc.com\",\n \"go-mpulse.net\",\n \"good.ta80.com\",\n \"googleadsserving.cn\",\n \"googleads.g.doubleclick.net\",\n \"googlecommerce.com\",\n \"googlesyndication.com\",\n \"goolpter.com\",\n \"gopig.io\",\n \"gorgon.youdao.com\",\n \"gosquared.com\",\n \"goto.sogou.com\",\n \"goto.www.iciba.com\",\n \"gotourl.xyz\",\n \"goufanli100.com\",\n \"gouwubang.com\",\n \"gouzhibao.cn\",\n \"govgift.com\",\n \"govids.net\",\n \"gp.jstv.com\",\n \"gpydym.cn\",\n \"gqswg.com\",\n \"grand.ele.me\",\n \"green.erne.co\",\n \"greenhouseglobal.cn\",\n \"greenxfs.down.123ch.cn\",\n \"gridsum.com\",\n \"gridsumdissector.cn\",\n \"gridsumdissector.com\",\n \"groupa.onlylady.com\",\n \"growingio.com\",\n \"gs307.com\",\n \"gso0.com\",\n \"gstat.bitauto.com\",\n \"gt.yy.com\",\n \"gt4ec.net\",\n \"gtags.net\",\n \"gtmucs.cn\",\n \"gu.qlogo.cn\",\n \"guang.lesports.com\",\n \"guang.sdsgwy.com\",\n \"guangzhuiyuan.com\",\n \"guangzizai.com\",\n \"guanjia.baidu.com\",\n \"guduopu.com\",\n \"guess.h.qhimg.com\",\n \"guestworld.tripod.lycos.com\",\n \"gugulonger.cn\",\n \"guidashu.com\",\n \"guitarpro.cc\",\n \"gum.criteo.com\",\n \"guohead.com\",\n \"guomob.com\",\n \"guoshennet.com\",\n \"gw5.push.mcp.weibo.cn\",\n \"gw6.push.mcp.weibo.cn\",\n \"gw630.com\",\n \"gx38.cn\",\n \"gxdhgb.com\",\n \"gxe.husky.sogou.com\",\n \"gyca9f.dahuangcheng.cn\",\n \"gydag.com\",\n \"gyrtg.com\",\n \"gz.hxdaka.com\",\n \"gz00005.top\",\n \"gzktpf.com\",\n \"gzlykj.cn\",\n \"gzmjnx.cn\",\n \"gzqudou.com\",\n \"h.canmg.cn\",\n \"h.holder.com.ua\",\n \"h.irs01.com\",\n \"h.laojiayoufang.com\",\n \"h.msn.com\",\n \"h.sora.yoyi.com.cn\",\n \"h01.hotrank.com.tw\",\n \"h1.18sd.cn\",\n \"h2.18sd.cn\",\n \"h5.holalauncher.com\",\n \"h5.jiumaster.com\",\n \"h5.pk1179.com\",\n \"h5.super-dreamers.com\",\n \"h5.taihao.cc\",\n \"h5-api.feiersmart.com\",\n \"h8.bec.com\",\n \"h9377c.com\",\n \"haitaoad.nosdn.127.net\",\n \"haiwai-ic.ksosoft.com\",\n \"haiwengji.net\",\n \"haiyunpush.com\",\n \"hanju18.net\",\n \"hao.7654.com\",\n \"hao.qquu8.com\",\n \"hao.tiandi.com\",\n \"hao.uc.cn\",\n \"hao123.xywy.com\",\n \"hao123rt.com\",\n \"hao549.com\",\n \"hao61.net\",\n \"hao916.com\",\n \"hao934.com\",\n \"haoghost.com\",\n \"haohaowan8.com\",\n \"haolew.com\",\n \"haoshengtoys.com\",\n \"haostat.qihoo.com\",\n \"hapic1.jhkxwl.com\",\n \"hascosafety.com\",\n \"hats.haibao.cn\",\n \"hbalx.cn\",\n \"hbdt.luomi.com\",\n \"hblinwei.com\",\n \"hbngfy.com\",\n \"hbyyzm.com\",\n \"hc.baidu.com\",\n \"hccms.com.cn\",\n \"hcreditx.com\",\n \"hd.jiedaibao.com\",\n \"hd.ylddq.com\",\n \"hda.maxli.cn\",\n \"hdad.baike.com\",\n \"hdb.maxli.cn\",\n \"hdggcdn.bayimob.com\",\n \"hdhkwl.com\",\n \"hdj.baidu.com\",\n \"he2d.com\",\n \"health1.12584.cn\",\n \"heavenmedia.v3g4s.com\",\n \"hechaocheng.cn\",\n \"heefwozhlxgz.com\",\n \"hefan365.com\",\n \"heib10.top\",\n \"heib12.top\",\n \"heimo.rrsdl.com\",\n \"hejban.youwatch.org\",\n \"hejingroup.cn\",\n \"help.baotangwang.cn\",\n \"help.yunaq.com\",\n \"hesxz.com\",\n \"heyzap.com\",\n \"hfjuki.com\",\n \"hfsteel.net\",\n \"hg417.bet\",\n \"hg89038.com\",\n \"hg89068.com\",\n \"hg89078.com\",\n \"hgame.com\",\n \"hh6666.com\",\n \"hhlian.com\",\n \"hhly88.com\",\n \"hhppyt.com\",\n \"hhqda.pop.t5yx.cn\",\n \"hi686.com\",\n \"hi760.com\",\n \"hi9377.com\",\n \"hiad.myweb.hinet.net\",\n \"hiad.vmall.com\",\n \"higame123.com\",\n \"hilltopads.net\",\n \"himandy.com\",\n \"hipersushiads.com\",\n \"histats.com\",\n \"hit.webcentre.lycos.co.uk\",\n \"hitlog2.chosun.com\",\n \"hitslink.com\",\n \"hivecn.cn\",\n \"hivedata.cc\",\n \"hjc1990.com\",\n \"hk.jtsh123.com\",\n \"hk.napi.ucweb.com\",\n \"hk9600.com\",\n \"hk-cdn.effectivemeasure.net\",\n \"hkfuy.com\",\n \"hl.kuzu.com\",\n \"hl.quw18.com\",\n \"hl2rcv.adobe.com\",\n \"hldwmly.com\",\n \"hlrcv.stage.adobe.com\",\n \"hmp33.com\",\n \"hmttoly.com\",\n \"hmyangshengji.com\",\n \"hnasd.com\",\n \"hnctsm.com\",\n \"hndiyikj.com\",\n \"hnxxjn.com\",\n \"hnyny.com\",\n \"hoisin.coocaatv.com\",\n \"home520.com\",\n \"hoplink.ksosoft.com\",\n \"hosting.miarroba.info\",\n \"hot.browser.miui.com\",\n \"hot.m.shouji.360tpcdn.com\",\n \"hot-mob.com\",\n \"hotrank.com.tw\",\n \"houdaolj.com\",\n \"houtai.2345.com\",\n \"hpd.baidu.com\",\n \"hpqxznpb.bid\",\n \"hqgjcm.com\",\n \"hr41.cn\",\n \"hr44.com\",\n \"hs.qhupdate.com\",\n \"hslyqs.com\",\n \"ht.www.sogou.com\",\n \"htfmbt.com\",\n \"htjsk.com\",\n \"html.350.com\",\n \"html.sunday8.com\",\n \"html.yuntzs.com\",\n \"httpdns.push.oppomobile.com\",\n \"huahuaka.com\",\n \"huashengtai.net\",\n \"huashuowork.com\",\n \"huaxinxunye.cn\",\n \"huayi65.com\",\n \"hub5pn.wap.sandai.net\",\n \"hubojd.com\",\n \"huichuan.sm.cn\",\n \"huimee.net\",\n \"huishenghuiying.com\",\n \"huishenghuiying.com.cn\",\n \"humanding.com\",\n \"hunpingou.com\",\n \"huodonghezi.com\",\n \"huoying666.com\",\n \"hv.code.tanwanyx.com\",\n \"hw6.com\",\n \"hwt.player888.cn\",\n \"hxadt.com\",\n \"hxspc.com\",\n \"hxstfxx.cn\",\n \"hxueu.code.weddingeeos.com\",\n \"hxyifu.com\",\n \"hxyx360.com\",\n \"hyfh.benbaisteel.com\",\n \"hyfyuan.com\",\n \"hyperpromote.com\",\n \"hypersnap.net\",\n \"hys4.com\",\n \"hystq.com\",\n \"hytgj.com\",\n \"hyz86.com\",\n \"hz.miercn.com\",\n \"hz.shouyoutv.com\",\n \"hzaibi.com\",\n \"hzdmacore.kejet.net\",\n \"hzhyhm.com\",\n \"hzsod71wov.me\",\n \"hzxfmc.com\",\n \"hzyuw.com\",\n \"i.bigmir.net\",\n \"i.clkservice.youdao.com\",\n \"i.dreamfull.cn\",\n \"i.flow.browser.oppomobile.com\",\n \"i.go.sohu.com\",\n \"i.haloapps.com\",\n \"i.hao61.net\",\n \"i.holalauncher.com\",\n \"i.huilixieye.net\",\n \"i.jiathis.com\",\n \"i.jyhwt.cn\",\n \"i.l.cnn.net\",\n \"i.liadm.com\",\n \"i.ma.social-touch.com\",\n \"i.mmcdn.cn\",\n \"i.ssix.io\",\n \"i.syasn.com\",\n \"i.tansuotv.com\",\n \"i.w55c.net\",\n \"i.zhuoyaju.com\",\n \"i1236.net\",\n \"i2.akjunshi.com\",\n \"i3818.com\",\n \"i5.akjunshi.com\",\n \"i92xue.com\",\n \"ia.ctags.cn\",\n \"iad.g.163.com\",\n \"iadc.qwapi.com\",\n \"iadmatvideo.nosdn.127.net\",\n \"iadmusicmat.music.126.net\",\n \"iads.xinmin.cn\",\n \"iadsdk.apple.com\",\n \"ib.adnxs.co\",\n \"ibafnw.cn\",\n \"ibanners.empoweredcomms.com.au\",\n \"ic.wps.cn\",\n \"icast.cn\",\n \"icdxc.com\",\n \"ichaosheng.com\",\n \"icn.southmoney.com\",\n \"ico.58pic.com\",\n \"icon.cnmo.com\",\n \"icons.mydrivers.com\",\n \"iconworkshop.cn\",\n \"id.jiathis.com\",\n \"id528.com\",\n \"ida.cnool.net\",\n \"idasai.com\",\n \"idcot.com\",\n \"idcqi.com\",\n \"identified.cn\",\n \"idianfang.com\",\n \"idm-su.baidu.com\",\n \"ids.deliver.ifeng.com\",\n \"ids1.deliver.ifeng.com\",\n \"idx.m.hub.sandai.net\",\n \"ie8eamus.com\",\n \"iebar.baidu.com\",\n \"ieonline.microsoft.com\",\n \"if1512.com\",\n \"ifengad.3g.ifeng.com\",\n \"iflyad.bj.openstorage.cn\",\n \"iframe.travel.yahoo.com\",\n \"ig.nukefans.net\",\n \"igj5y.yongchanghengyuan.com\",\n \"ih.adscale.de\",\n \"ihualun.com\",\n \"ihuanmei.com\",\n \"iia1.pikacn.com\",\n \"iiad.com\",\n \"iiewl.com\",\n \"iii.6park.com\",\n \"iis1.deliver.ifeng.com\",\n \"iis3g.deliver.ifeng.com\",\n \"iisl7wpf.me\",\n \"ikcode.baidu.com\",\n \"il8r.com\",\n \"im.jpush.cn\",\n \"im.ov.yahoo.co.jp\",\n \"im1.56zzw.com\",\n \"im64.jpush.cn\",\n \"ima3vpaid.appspot.com\",\n \"imads.rediff.com\",\n \"image.139y.com\",\n \"image.9duw.com\",\n \"image.box.xiaomi.com\",\n \"image.fsyule.net\",\n \"image.gentags.com\",\n \"image.haiyunx.com\",\n \"image.hh010.com\",\n \"image.hj217.com\",\n \"image.p4p.sogou.com\",\n \"image.qj175.com\",\n \"image.zzd.sm.cn\",\n \"imagelx.yidianzixun.com\",\n \"images.avsmt.cn\",\n \"images.chinaz.com\",\n \"images.enet.com.cn\",\n \"images.fastclick.net\",\n \"images.gxsky.com\",\n \"images.intellitxt.com\",\n \"images.millennialmedia.com\",\n \"images.pagechoice.net\",\n \"images.sohu.com\",\n \"images.startappservice.com\",\n \"images.tyyjzs.cn\",\n \"images9999.com\",\n \"imageter.com\",\n \"imagzine.oppomobile.com\",\n \"imedia.bokecc.com\",\n \"imeijiajia.com\",\n \"imfsr.lenovomm.com\",\n \"img.12584.cn\",\n \"img.3sjt.com\",\n \"img.88ads.com\",\n \"img.9duw.com\",\n \"img.ad.zhangyue.com\",\n \"img.adbox.sina.com.cn\",\n \"img.adnyg.com\",\n \"img.amp.ad.sina.com.cn\",\n \"img.cmm.xmfish.com\",\n \"img.cxxyft.com\",\n \"img.dawenxue.org\",\n \"img.dydab.com\",\n \"img.ercfh.com\",\n \"img.fd7c.com\",\n \"img.feitian001.com\",\n \"img.gaore.com\",\n \"img.gz9d.com\",\n \"img.il8r.com\",\n \"img.img18.com\",\n \"img.jgchq.com\",\n \"img.jizzads.com\",\n \"img.kanuxian.cn\",\n \"img.khlxw.com\",\n \"img.kuwanpx.com\",\n \"img.libdd.com\",\n \"img.ma.social-touch.com\",\n \"img.meipic.net\",\n \"img.qdscgj.com\",\n \"img.qqgeshou.com\",\n \"img.s8bbs.com\",\n \"img.scupio.com\",\n \"img.sheyuansu.com\",\n \"img.supfast.net\",\n \"img.tan5858.com\",\n \"img.taotaosou.cn\",\n \"img.tcdxt.com\",\n \"img.toppr.com.cn\",\n \"img.twcczhu.com\",\n \"img.uyangyong.cn\",\n \"img.wan.sogou.com\",\n \"img.wuben56.com\",\n \"img.xa9t.com\",\n \"img.xcy8.com\",\n \"img.xiacaidd.com\",\n \"img.xuenb.com\",\n \"img.yingshidiguo.cn\",\n \"img.yuyue007.cn\",\n \"img.zsj18.com\",\n \"img.zuowen8.com\",\n \"img.zx590.com\",\n \"img0.egou.com\",\n \"img01.taotaosou.cn\",\n \"img1.126.net\",\n \"img1.18183.com\",\n \"img1.jintang114.org\",\n \"img1.km.com\",\n \"img1.mekbet.com\",\n \"img1.nend.net\",\n \"img1.pcfg.cache.wps.cn\",\n \"img1.pszyzxh.org\",\n \"img18.com\",\n \"img2.126.net\",\n \"img2.578965.com\",\n \"img2.cs153.com\",\n \"img2.hrccb.com\",\n \"img2.jiuzhilan.com\",\n \"img2.km.com\",\n \"img2.qekun.com\",\n \"img3.126.net\",\n \"img3.fy1g.com\",\n \"img3.km.com\",\n \"img6.126.net\",\n \"img80.net\",\n \"img-ad.oupeng.com\",\n \"imgad.thepaper.cn\",\n \"imgad0.3conline.com\",\n \"imgad0.pconline.com.cn\",\n \"imgadpai.thepaper.cn\",\n \"imgapp.yeyou.com\",\n \"imgc.cymzc.com\",\n \"imgcdn.wapx.cn\",\n \"img-cdn-spot.ymcdn.cn\",\n \"img-dsp.oss-cn-beijing.aliyuncs.com\",\n \"imges.wu65.com\",\n \"imgg.marketgid.com\",\n \"imgg.mgid.com\",\n \"imgp.cymzc.com\",\n \"imgsreview.dftoutiao.com\",\n \"imindmap.cc\",\n \"immob.cn\",\n \"imneinei.com\",\n \"i-mobile.co.jp\",\n \"imp.asahi.com\",\n \"imp.gentags.net\",\n \"imp.go.sohu.com\",\n \"imp.madserving.com\",\n \"imp.pdb.madserving.com\",\n \"imp.xgo.com.cn\",\n \"imp.zdnet.com.cn\",\n \"imp.zol.com.cn\",\n \"impression.gridsumdissector.com\",\n \"impservice.dictapp.youdao.com\",\n \"impservice.youdao.com\",\n \"impservice2.youdao.com\",\n \"impservicetest.dictapp.youdao.com\",\n \"impservice-test.dictapp.youdao.com\",\n \"imrworldwide.com\",\n \"in.gyeet.com\",\n \"in.jxhcyc.com\",\n \"in.mengpr.com\",\n \"in.mgwcn.com\",\n \"in.qzkxt.com\",\n \"in.zog.link\",\n \"in1.feed.uu.cc\",\n \"in1.secure.uu.cc\",\n \"inad.com\",\n \"inapp.1sapp.com\",\n \"inccnd.com\",\n \"inclk.com\",\n \"include.xs2345.com\",\n \"index.woai310.com\",\n \"indieclick.3janecdn.com\",\n \"info.downsave.com\",\n \"info.gomlab.com\",\n \"info.meihua.docer.com\",\n \"info.pinyin.sogou.com\",\n \"info.sec.miui.com\",\n \"info.stockstar.com\",\n \"info.yitsoftware.com\",\n \"info4.video.qq.com\",\n \"info6.video.qq.com\",\n \"infocenter.meizu.com\",\n \"ingameads.gameloft.com\",\n \"ini.litingxin.cn\",\n \"ini.update.360safe.com\",\n \"init.phpwind.com\",\n \"init.phpwind.net\",\n \"init.startappexchange.com\",\n \"innity.com\",\n \"innity.net\",\n \"inoprosport.su\",\n \"insenz.com\",\n \"inside.bitcomet.com\",\n \"inskin.vo.llnwd.net\",\n \"inst.360safe.com\",\n \"instabug.com\",\n \"install.kugou.com\",\n \"install.sidesearch.lycos.com\",\n \"install2.kugou.com\",\n \"instreet.cn\",\n \"int.dpool.sina.com.cn\",\n \"inte.theta.sogoucdn.com\",\n \"intellitxt.com\",\n \"intely.cn\",\n \"inter1ads.com\",\n \"interaction.bayimob.com\",\n \"interactive.huanqiu.com\",\n \"interest.mix.sina.com.cn\",\n \"ioc.mmakd.top\",\n \"ios.bugly.qq.com\",\n \"ios.video.mpush.qq.com\",\n \"ios-dc.51y5.net\",\n \"ios-informationplatform.wps.cn\",\n \"iosipa.b0.upaiyun.com\",\n \"ip.hivps.xyz\",\n \"ip2.pxene.com\",\n \"ipengtai.huanqiu.com\",\n \"iperceptions.com\",\n \"iphonelog.shouji.baofeng.com\",\n \"ipic.staticsdo.com\",\n \"ipinyou.com\",\n \"ipm.atm.cp31.ott.cibntv.net\",\n \"ipm.atm.youku.com\",\n \"iqiyi.irs01.com\",\n \"ir.mail.126.com\",\n \"ir.mail.163.com\",\n \"ir.mail.yeah.net\",\n \"iroby.com\",\n \"irpmt.mail.163.com\",\n \"irs01.com\",\n \"irs01.net\",\n \"irs09.com\",\n \"ishop789.com\",\n \"ishowbg.com\",\n \"istreamsche.com\",\n \"itaoxiaoshuo.com\",\n \"item.ttkvod.com\",\n \"items.bingdiantao.com\",\n \"its.fugetech.com\",\n \"its-dori.tumblr.com\",\n \"iutr.uozwys.top\",\n \"iuuff.com\",\n \"ivy.pcauto.com.cn\",\n \"ivy.pcbaby.com.cn\",\n \"ivy.pclady.com.cn\",\n \"ivy.pconline.com.cn\",\n \"iwan.sogou.com\",\n \"iwanad.baidu.com\",\n \"ixpub.net\",\n \"j.6avz.com\",\n \"j.baminw.cn\",\n \"j.biquge520.cc\",\n \"j.br.baidu.com\",\n \"j.ccnovel.com\",\n \"j.chaorenjiaoshi.com\",\n \"j.dipowang.cn\",\n \"j.fd7c.com\",\n \"j.hbwcl.com\",\n \"j.hongyangpai.com\",\n \"j.jimeilm.com\",\n \"j.kfd3sm2c.com\",\n \"j.qijijs.top\",\n \"j.qiqivv.com\",\n \"j.qiqiww.com\",\n \"j.s11.cn\",\n \"j.sc1369.com\",\n \"j.sdqoi2d.com\",\n \"j.wan.liebao.cn\",\n \"j.wit.qq.com\",\n \"j.xinshipu.com\",\n \"j.yljiaoluo.com\",\n \"j.ytbt.cc\",\n \"j.zhdap.com\",\n \"j1.piaobing.com\",\n \"j17.shangc.net\",\n \"j17.xiumu.cn\",\n \"j520s.gzcl999.cn\",\n \"j7182.hfxcsl.cn\",\n \"ja.gamersky.com\",\n \"ja1.gamersky.com\",\n \"ja9377.com\",\n \"jack.okkkk.com\",\n \"jackaow.com\",\n \"jagcn.com\",\n \"jav23.com\",\n \"javhd.com\",\n \"jb.4hw.com.cn\",\n \"jb.asqql.com\",\n \"jb.dianshu119.com\",\n \"jb.eastlady.cn\",\n \"jb.ecar168.cn\",\n \"jb.mbaidu.top\",\n \"jb.mnkan.com\",\n \"jb.tupianzj.com\",\n \"jbcbuy.com\",\n \"jbflil.cn\",\n \"jbyy010.com\",\n \"jc.anhuilitian.net\",\n \"jc.xuqinqi.cn\",\n \"jc1.dayfund.cn\",\n \"jct.maptu.cn\",\n \"jczzjx.com\",\n \"jd.c-ptsp.com.cn\",\n \"jdb.jiudingcapital.cn\",\n \"jdb.jiudingcapital.com\",\n \"jddaw.com\",\n \"jdg.bjygfd.com\",\n \"jdkic.com\",\n \"jdlcg.cn\",\n \"jdlhg.com\",\n \"jdw.zjuwjdc.com\",\n \"jebe.renren.com\",\n \"jebe.xnimg.cn\",\n \"jellyfish.pandora.xiaomi.com\",\n \"jermr.com\",\n \"jesgoo.com\",\n \"jf.winads.cn\",\n \"jfhe.0769371.com\",\n \"jfm4.pop.baofeng.net\",\n \"jfqkj.com\",\n \"jgchq.com\",\n \"jghcy.com\",\n \"jhakie.com\",\n \"jhtcdj.com\",\n \"jhzl001.com\",\n \"ji.dazhantai.com\",\n \"jiaheyonggu.com\",\n \"jiajv.net\",\n \"jianbaimei.com\",\n \"jianduankm.com\",\n \"jianmei123.com\",\n \"jiansuo.dsxdn.com\",\n \"jiaoben.eastday.com\",\n \"jiaoben.ganji.cn\",\n \"jiaoben.jucanw.com\",\n \"jiaoben.junmeng.com\",\n \"jiaoben.xinshipu.cn\",\n \"jias.haotxt.com\",\n \"jiathis.com\",\n \"jiawen88.com\",\n \"jiayi1.oss-cn-shanghai.aliyuncs.com\",\n \"jiedaibao.com\",\n \"jiehantai.com\",\n \"jiehunmishu.com\",\n \"jifeidandar.com\",\n \"jifen.2345.com\",\n \"jihehuaban.com\",\n \"jihehuaban.com.cn\",\n \"jimdo.com\",\n \"jimeilm.com\",\n \"jindu179.com\",\n \"jing.58.com\",\n \"jingdian230.meilika.net\",\n \"jinghuazhijia.com\",\n \"jinsha11833.com\",\n \"jinshagt222.com\",\n \"jira.vpon.com\",\n \"jisucn.com\",\n \"jiu.njdkgm.com\",\n \"jiubuhua.com\",\n \"jiuku.cc\",\n \"jiyou2014.com\",\n \"jizzads.com\",\n \"jj123.com.cn\",\n \"jjhd47.115seo.com\",\n \"jjx.xjtxcj.com\",\n \"jjxgly.com\",\n \"jjyy.gaopengqcdz.cn\",\n \"jk939.com\",\n \"jkjjkj.top\",\n \"jkmxy.com\",\n \"jl027.com\",\n \"jlssbz.com\",\n \"jmonitor.jiuzhilan.com\",\n \"jmsyzj.com\",\n \"jmxlaser.com\",\n \"jndczg.com\",\n \"jnrsjm.com\",\n \"jnsdkjzs.com\",\n \"jnsz.net.cn\",\n \"jnyngg.cn\",\n \"johtzj.com\",\n \"jointreport-switch.com\",\n \"jossuer.net\",\n \"joyfuldoors.com\",\n \"jp88.cc\",\n \"jpg.cooguo.com\",\n \"jpg.inte.sogoucdn.com\",\n \"jph.itiexue.net\",\n \"jpush.cn\",\n \"jpush.html5.qq.com\",\n \"jqmt.qq.com\",\n \"jqz9.com\",\n \"jrdkc.com\",\n \"jrhaigou.com\",\n \"jrpt.jrptweb.org\",\n \"js.05sun.com\",\n \"js.133u.com\",\n \"js.139y.com\",\n \"js.1688988.com\",\n \"js.2011.8684.com\",\n \"js.45bubu.com\",\n \"js.4hw.com.cn\",\n \"js.5068.com\",\n \"js.51taifu.com\",\n \"js.578965.com\",\n \"js.5iydz.com\",\n \"js.9669.cn\",\n \"js.adxkj.com\",\n \"js.bju888.com\",\n \"js.bxwns.com\",\n \"js.bxwxtxt.com\",\n \"js.cdjqjy.com\",\n \"js.cncrk.com\",\n \"js.cnmo.com\",\n \"js.cnscdj.com\",\n \"js.ctags.cn\",\n \"js.daxueshengqiandai.com\",\n \"js.dkqapp.cn\",\n \"js.duotegame.com\",\n \"js.ea3w.com\",\n \"js.feitian001.com\",\n \"js.fengniao.com\",\n \"js.firefang.cn\",\n \"js.gewuwen.com\",\n \"js.hkslg520.com\",\n \"js.hslyqs.com\",\n \"js.icast.cn\",\n \"js.idgdmg.com.cn\",\n \"js.jianbaimei.com\",\n \"js.jxabp.com.cn\",\n \"js.lieqitianxia.cn\",\n \"js.mbaidu.top\",\n \"js.mingxianshanghang.cn\",\n \"js.mnkan.com\",\n \"js.moatads.com\",\n \"js.mumayi.net\",\n \"js.paochala.net\",\n \"js.ptmind.com\",\n \"js.pub.tom.com\",\n \"js.pyangzi.com\",\n \"js.revsci.net\",\n \"js.ruiwen.com\",\n \"js.saiqizhi.com\",\n \"js.sanwen.net\",\n \"js.soduso.cc\",\n \"js.soonyou123.com\",\n \"js.start1999.com\",\n \"js.szande.com.cn\",\n \"js.ubaike.cn\",\n \"js.um0592.com\",\n \"js.union-wifi.com\",\n \"js.wo-x.cn\",\n \"js.wu65.com\",\n \"js.xiansuper.com\",\n \"js.xtgreat.com\",\n \"js.xuexila.com\",\n \"js.ydeprint.com\",\n \"js.yixui.com\",\n \"js.ylunion.com\",\n \"js.yoyi.tv\",\n \"js.zol.com.cn\",\n \"js.zyrfanli.com\",\n \"js1.2abc8.com\",\n \"js1.nend.net\",\n \"js-1.pchome.net\",\n \"js1.xbaixing.com\",\n \"js1.zuocai.tv\",\n \"js1151.yongkang6.com\",\n \"js1151.zhudiaosz.com\",\n \"js1157.yongkang6.com\",\n \"js123.0937jyg.com\",\n \"js1516.0937jyg.com\",\n \"js1517.0937jyg.com\",\n \"js205.dupinpu.com\",\n \"js2254.hfxcsl.cn\",\n \"js2553.xjzyq.com\",\n \"js257.0937jyg.com\",\n \"js2672.xjzyq.com\",\n \"js3492.yongkang6.com\",\n \"js3743.yongkang6.com\",\n \"js3768.zhudiaosz.com\",\n \"js3810.yongkang6.com\",\n \"js3810.zhudiaosz.com\",\n \"js4.eastmoney.com\",\n \"js412.0937jyg.com\",\n \"js412.yexfes.com\",\n \"js412.yqjxzw.com\",\n \"js4163.yongkang6.com\",\n \"js4273.zhudiaosz.com\",\n \"js453.zhudiaosz.com\",\n \"js50.yxlady.com\",\n \"js5162.yongkang6.com\",\n \"js6882.jianbangjiaoyu.com\",\n \"js6882.mengchengbao.com\",\n \"js7004.hnfpgm.com\",\n \"js7129.dlkjgjmy.com\",\n \"js7129.shxqeps.com\",\n \"js7152.shxqeps.com\",\n \"js74.0937jyg.com\",\n \"js74.yexfes.com\",\n \"js74.yqjxzw.com\",\n \"js7405.mengchengbao.com\",\n \"js84.enyayinxiang.com\",\n \"js883.hnfpgm.com\",\n \"js883.yongkang6.com\",\n \"js9318.bllzgqbyp.com\",\n \"jsadt.com\",\n \"js-agent.newrelic.com\",\n \"js-apac-ss.ysm.yahoo.com\",\n \"jsb.qianzhan.com\",\n \"jsc.adskeeper.co.uk\",\n \"jsc.marketgid.com\",\n \"jsc.mgid.com\",\n \"jscdn.99pps.com\",\n \"jscode.jbzj.com\",\n \"jsjs.nthyn.com\",\n \"jskrnekewe.mofans.net\",\n \"jsm.39yst.com\",\n \"jsm.9939.com\",\n \"jsmwd.com\",\n \"jsnp.golden1.sogou.com\",\n \"jsnywl.kfi8.com\",\n \"json.gewuwen.com\",\n \"jspg.cc\",\n \"jsqmt.qq.com\",\n \"jssd.uumeitu.com\",\n \"jt.yunxiufang.net\",\n \"jtug.code.poyang.com\",\n \"jtxh.net\",\n \"jtys8.com\",\n \"ju33.com\",\n \"juicyads.com\",\n \"jump.luna.58.com\",\n \"jumpe.58xmgys.com\",\n \"jumpluna.58.com\",\n \"jumpm.58xmgys.com\",\n \"jundazulin.com\",\n \"junfull.com\",\n \"juren0.com\",\n \"jusha.com\",\n \"jutou5.com\",\n \"juzi.cn\",\n \"juzilm.com\",\n \"jwg365.cn\",\n \"jwpltx.com\",\n \"jwqj.net\",\n \"jwz.3conline.com\",\n \"jx5m.com\",\n \"jxad.jx163.com\",\n \"jxbjt.com\",\n \"jxfxsw.com\",\n \"jxjzny.com\",\n \"jxlog.istreamsche.com\",\n \"jxlqgs.com\",\n \"jxxiangchu.com\",\n \"jyc.njxczy.com\",\n \"jyd.fjzdmy.com\",\n \"jystea.com\",\n \"jyz.fjtzjy.com\",\n \"jzkapp.com\",\n \"jzm81.com\",\n \"k.85wa.cn\",\n \"k.ctsywy.com\",\n \"k1w5.me\",\n \"k2team.kyiv.ua\",\n \"k3bos.com\",\n \"kafka8.com\",\n \"kaitongyewu.com\",\n \"karma.mdpcdn.com\",\n \"kas.keydot.net\",\n \"kawa11.space\",\n \"kbnetworkz.s3.amazonaws.com\",\n \"kddtri.cn\",\n \"kejet.com\",\n \"kejet.net\",\n \"kele4.com\",\n \"ker.pic2pic.site\",\n \"kermit.macnn.com\",\n \"keryt.jnservo.com\",\n \"ketchapp.org\",\n \"keydot.net\",\n \"keyrun.cn\",\n \"keyrun.com\",\n \"keyshot.cc\",\n \"keystone.mwbsys.com\",\n \"keyyou.net\",\n \"kfewaz.zh1155.com\",\n \"kfhuihe.net\",\n \"kfluoa.com\",\n \"kgcjgsa8.net\",\n \"kgmobilestat.kugou.com\",\n \"kguke.com\",\n \"kho3au7l4z.me\",\n \"kicnse.com\",\n \"kingdeecn.cn\",\n \"kingwam.com\",\n \"kio.quanliyouxi.cn\",\n \"kiss.blockplus.cc\",\n \"kjgen.com\",\n \"kk7kk.com\",\n \"kkcaicai.com\",\n \"kkpgv.kankan.com\",\n \"kkpgv2.kankan.com\",\n \"kld666.com\",\n \"kldmm.com\",\n \"klsdmr.com\",\n \"kl-toys.com\",\n \"klz28.com\",\n \"km.jianduankm.com\",\n \"kmadou.com\",\n \"kmd365.com\",\n \"kmwqxqh.com\",\n \"kn.aishake.cn\",\n \"kn.archrug.com\",\n \"kn.barnfps.com\",\n \"kn.bjbrtc.com\",\n \"kn.chapnap.com\",\n \"kn.chgdf.cn\",\n \"kn.czzdf.com\",\n \"kn.dyscsm.cn\",\n \"kn.gzcce.cn\",\n \"kn.jzhrty.cn\",\n \"kn.nykps.com\",\n \"kn.qhdfxkj.com\",\n \"kn.qqqmdq.com\",\n \"kn.qzdaren.com\",\n \"kn.ynmhg.cn\",\n \"kn.zstjy.com\",\n \"kn.zzdahan.com\",\n \"knet.cn\",\n \"knnwdyou.com\",\n \"kob.adxkj.com\",\n \"kochava.com\",\n \"kod4pc293.com\",\n \"koowo.com\",\n \"koukou7.com\",\n \"kovjo.com\",\n \"kqy1.com\",\n \"kr.sybspools.com\",\n \"krux.net\",\n \"ksdsuzhou.com\",\n \"ksr.juuhe.com\",\n \"ksrsy.com\",\n \"kstj.baidu.com\",\n \"kt220.com\",\n \"ktivn.uranus.sogou.com\",\n \"ktunions.com\",\n \"ktv0311.com\",\n \"ku63.com\",\n \"ku9377.com\",\n \"kuaigao.rrsdl.com\",\n \"kuaikaiapp.com\",\n \"kuaikan.netmon.360safe.com\",\n \"kuaipai666.cn\",\n \"kuaizip.com\",\n \"kualianyingxiao.cn\",\n \"kudifish.com\",\n \"kuguopush.com\",\n \"kumihua.com\",\n \"kuwoyy.com\",\n \"kuyic.m.gxwztv.com\",\n \"kuzai.cooguo.com\",\n \"kw.ra.icast.cn\",\n \"kwmsg.kuwo.cn\",\n \"kwurl.ucweb.com\",\n \"kxlogo.knet.cn\",\n \"kxmav2.com\",\n \"kxrxh.com\",\n \"kyad88.com\",\n \"kyzhecmvpiaw.com\",\n \"l.adiers.com\",\n \"l.betrad.com\",\n \"l.minisplat.cn\",\n \"l.mnjkw.cn\",\n \"l.supfast.net\",\n \"l.ujian.cc\",\n \"l.yidianzixun.com\",\n \"l1.soarfi.cn\",\n \"l2.soarfi.cn\",\n \"l9bdhcgihw.neihanw.com\",\n \"labs.ra.icast.cn\",\n \"laigame7.com\",\n \"laiququan.com\",\n \"lajizhan.org\",\n \"lan.btwan5.com\",\n \"langchars.com\",\n \"langjiyisheng.com\",\n \"lansha.tv\",\n \"lanxiangji.com\",\n \"laomaotao.net\",\n \"laoqu123.com\",\n \"lashou1000.com\",\n \"lb.gtimg.com\",\n \"lb.statsevent.com\",\n \"lbstatic-a.akamaihd.net\",\n \"lbszb.tongbu.com\",\n \"lc.jiathis.com\",\n \"lcs.dev.surepush.cn\",\n \"ld.mediaget.com\",\n \"ldpgl.code.mytanwan.com\",\n \"lds.lenovomm.com\",\n \"lds.zui.com\",\n \"ldy.350.com\",\n \"ldy.adqku.cn\",\n \"le4le.com\",\n \"leadbolt.net\",\n \"leadboltads.net\",\n \"leadboltapps.net\",\n \"leadboltmobile.net\",\n \"ledou.dl.uu.cc\",\n \"leeyuoxs.com\",\n \"legozu.com\",\n \"lele999.com\",\n \"lenzmx.com\",\n \"lessplay.com\",\n \"letv.irs01.com\",\n \"leztc.com\",\n \"lflili.com\",\n \"lfyuanai.com\",\n \"lg2.jointreport-switch.com\",\n \"lg4.jointreport-switch.com\",\n \"lhafy.com\",\n \"lhengilin.com\",\n \"lhusy.com\",\n \"li.anyysz.com\",\n \"liangao.com\",\n \"liangziweixg.com\",\n \"lib.haotv8.com\",\n \"liba.haotv8.com\",\n \"libs.tvmao.cn\",\n \"license.lumion3d.com\",\n \"license.lumion3d.net\",\n \"licenses.ashampoo.com\",\n \"licensing.tableausoftware.com\",\n \"life.e0575.com\",\n \"life.imagepix.org\",\n \"lightson.vpsboard.com\",\n \"linezing.com\",\n \"lingdian98.com\",\n \"linkbide.com\",\n \"linkeye.ximalaya.com\",\n \"linkpage.cn\",\n \"links.services.disqus.com\",\n \"linktech.cn\",\n \"linyao.dxsdb.com\",\n \"lishuanghao.com\",\n \"listenother.com\",\n \"listlog.baofeng.net\",\n \"liuliguo.com\",\n \"live.tvpot.daum.net\",\n \"livehapp.com\",\n \"livep.l.ott.video.qq.com\",\n \"lives.l.cp81.ott.cibntv.net\",\n \"lives.l.ott.video.qq.com\",\n \"lives.l.qq.com\",\n \"liveupdate.mac.sandai.net\",\n \"lixiangmo.com\",\n \"ljrtb.cn\",\n \"lkf1.m.sanhao3.com\",\n \"ll.a.hulu.com\",\n \"ll.gxsky.com\",\n \"ll.hudong.com\",\n \"ll.songlaoban.cn\",\n \"ll38.com\",\n \"lm.dawenxue.org\",\n \"lm.licenses.adobe.com\",\n \"lm.souid.com\",\n \"lm.xiashu.la\",\n \"lml.jfjsp.com\",\n \"lmlicenses.wip4.adobe.com\",\n \"lmwap.awtks.com\",\n \"lndjj.com\",\n \"lnk0.com\",\n \"lnk8z.com\",\n \"lnr2.com\",\n \"load77.exelator.com\",\n \"loading.baofeng5.baofeng.net\",\n \"loadm.exelator.com\",\n \"loandatec.com\",\n \"localnetwork.uop\",\n \"localytics.com\",\n \"location.ximalaya.com\",\n \"locdrop.query.yahoo.com\",\n \"log1.17173.com\",\n \"log1.molitv.cn\",\n \"log2.air.yoyi.com.cn\",\n \"log2.molitv.cn\",\n \"log-dmp.suishenyun.cn\",\n \"logonext.tv.kuyun.com\",\n \"logoshejishi.com\",\n \"logstat.caixin.com\",\n \"logupdate.avlyun.sec.miui.com\",\n \"lol.pnhfc.com\",\n \"loldy.jiangmg.com\",\n \"lomark.cn\",\n \"londonprivaterentals.standard.co.uk\",\n \"looky.hyves.org\",\n \"lottery.kuaiya.cn\",\n \"lotuseed.com\",\n \"lovestyl.com\",\n \"lovfp.com\",\n \"lp.jiuzhilan.com\",\n \"lp.startapp.com\",\n \"lp1901.com\",\n \"lpsxssm.com\",\n \"lqmohun.com\",\n \"lrswl.com\",\n \"ls.webmd.com\",\n \"lsxmg.com\",\n \"ltcprtc.com\",\n \"ltheanine.cn\",\n \"lthxz.cn\",\n \"lu.sogou.com\",\n \"lubosheng.cn\",\n \"lucting.cn\",\n \"lufax.com\",\n \"luotediao.net\",\n \"lvjian66.com\",\n \"lw1.cdmediaworld.com\",\n \"lw2.gamecopyworld.com\",\n \"lwnne.cn\",\n \"lwq.wangketuan.com\",\n \"lx167.com\",\n \"lxcdn.dl.files.xiaomi.net\",\n \"lxqcgj.com\",\n \"lxting.com\",\n \"lx-upload-log.yidianzixun.com\",\n \"lyaeccn.com\",\n \"lyapi.1391.com\",\n \"lycos-eu.imrworldwide.com\",\n \"lyhdream.com\",\n \"lyjk.1391.com\",\n \"lynndollin.com\",\n \"lyrymy.com\",\n \"lytubaobao.com\",\n \"lyunsd.cn\",\n \"lyztdz.com\",\n \"lz.chaelc.com\",\n \"lz.whafwl.com\",\n \"lzjycy.com\",\n \"lzmm8.com\",\n \"m.027blzs.com\",\n \"m.0531mnk.net\",\n \"m.107279.com\",\n \"m.118ex.cn\",\n \"m.1768.com\",\n \"m.1919388.net\",\n \"m.28487.net\",\n \"m.3987.com\",\n \"m.495495.com\",\n \"m.51xmgys.com\",\n \"m.52tushuo.com\",\n \"m.551144.com\",\n \"m.640640.com\",\n \"m.649649.com\",\n \"m.7180443.com\",\n \"m.77vcd.com\",\n \"m.937920.com\",\n \"m.abfirst.cn\",\n \"m.acaox.com\",\n \"m.achig.com\",\n \"m.ad.zhangyue.com\",\n \"m.adaog.com\",\n \"m.adxpop.com\",\n \"m.afoux.com\",\n \"m.anmeilai.net\",\n \"m.anzhuotan.com\",\n \"m.apxyz.com\",\n \"m.aqiudaohang.com\",\n \"m.assigned.cn\",\n \"m.aty.cp45.ott.cibntv.net\",\n \"m.aty.snmsohu.aisee.tv\",\n \"m.axsre.com\",\n \"m.baidu.com.yiqisee.cn\",\n \"m.baidu.com.zhiduo.org\",\n \"m.bailingjiankang.com\",\n \"m.baiyangzs.com\",\n \"m.bapkt.com\",\n \"m.bbvjs.com\",\n \"m.bdiae.com\",\n \"m.beacon.sina.com.cn\",\n \"m.bentengcn.com\",\n \"m.biquge5200.cc\",\n \"m.bokanedu.net\",\n \"m.bsnnk.com\",\n \"m.bss.pandora.xiaomi.com\",\n \"m.bvoer.com\",\n \"m.bvosv.com\",\n \"m.casbanlly.com\",\n \"m.cbeif.com\",\n \"m.ccunf.com\",\n \"m.cdfzcz.com\",\n \"m.cenrs.com\",\n \"m.chenhuia.com\",\n \"m.chexiw.com\",\n \"m.chfuw.com\",\n \"m.cjieh.com\",\n \"m.ckikq.com\",\n \"m.clkservice.youdao.com\",\n \"m.cocounion.com\",\n \"m.codlw.com\",\n \"m.coenr.com\",\n \"m.couas.com\",\n \"m.cqytjzgc.com\",\n \"m.ctsywy.com\",\n \"m.cudaojia.com\",\n \"m.cuoas.com\",\n \"m.cuoss.com\",\n \"m.daishuxy.com\",\n \"m.dante2007.com\",\n \"m.data.mob.com\",\n \"m.dbaiz.com\",\n \"m.dgaoz.com\",\n \"m.diogv.com\",\n \"m.djhhy.com\",\n \"m.dnfeu.com\",\n \"m.doodlemobile.com\",\n \"m.dsjre.com\",\n \"m.du1du.org\",\n \"m.duias.com\",\n \"m.duobao999.com\",\n \"m.dxmci.com\",\n \"m.edo5.com\",\n \"m.ee-skin.com\",\n \"m.ee-vip.net\",\n \"m.efeiy.com\",\n \"m.ehxyz.com\",\n \"m.emgwq.com\",\n \"m.enjuk.com\",\n \"m.ennmt.com\",\n \"m.fbaix.com\",\n \"m.fbaot.com\",\n \"m.fcaot.com\",\n \"m.fcuit.com\",\n \"m.fecjf.cn\",\n \"m.feirs.com\",\n \"m.fengwanwl.com\",\n \"m.fenrs.com\",\n \"m.fhxsw.org\",\n \"m.fimky.com\",\n \"m.fkkse.com\",\n \"m.fkogs.com\",\n \"m.focuscat.com\",\n \"m.fouas.com\",\n \"m.foumm.com\",\n \"m.fstaw.com\",\n \"m.fwjoi.com\",\n \"m.fxbga.com\",\n \"m.fzyda.com\",\n \"m.gameyun907.net\",\n \"m.ganrs.com\",\n \"m.gbieg.com\",\n \"m.gcaij.com\",\n \"m.gcheg.com\",\n \"m.gdt.vip1790.cn\",\n \"m.gglay.com\",\n \"m.gtiou.com\",\n \"m.gtnde.com\",\n \"m.guaas.com\",\n \"m.guanren11.com\",\n \"m.guanren5.com\",\n \"m.guanren6.com\",\n \"m.guanren9.com\",\n \"m.guifei99.com\",\n \"m.gujinyue.com\",\n \"m.gwdqp.com\",\n \"m.gxkyl.com\",\n \"m.haowj.com.cn\",\n \"m.harbinbaojia.net\",\n \"m.hellomingpian.com\",\n \"m.heygugu.com\",\n \"m.hhllyt.com\",\n \"m.hissq.com\",\n \"m.hk7799.net\",\n \"m.hkmqp.com\",\n \"m.hmzsfmjc.com\",\n \"m.hogyp.com\",\n \"m.hot-mob.com\",\n \"m.hpfjy.com\",\n \"m.hpzyl.com\",\n \"m.hsbkr.com\",\n \"m.htper.com\",\n \"m.huanyuexpress.com\",\n \"m.huyulh.com\",\n \"m.hyzui.com\",\n \"m.icyrd.com\",\n \"m.ienkdaged.cn\",\n \"m.ienkdago.cn\",\n \"m.infvb.com\",\n \"m.irauz.com\",\n \"m.irkuj.com\",\n \"m.iruad.com\",\n \"m.ishowms.com\",\n \"m.jcwwxn.com\",\n \"m.jdaot.com\",\n \"m.jgkto.com\",\n \"m.jhcgood.com\",\n \"m.jieyixiu.com\",\n \"m.jiirz.com\",\n \"m.jinchaoyu.com\",\n \"m.jioeg.com\",\n \"m.jkert.com\",\n \"m.jlkja.com\",\n \"m.jltdbyq.com\",\n \"m.joyxv.com\",\n \"m.juyzr.com\",\n \"m.jwiyr.com\",\n \"m.jyhwt.cn\",\n \"m.kcooy.com\",\n \"m.kejet.net\",\n \"m.kewro.com\",\n \"m.khuoy.com\",\n \"m.kjfhe.com\",\n \"m.kjhfy.com\",\n \"m.kl6636.net\",\n \"m.ksttwz.com\",\n \"m.kubiqq.com\",\n \"m.kwjkd.com\",\n \"m.kxhie.com\",\n \"m.laigame7.net\",\n \"m.lancedu.com\",\n \"m.laojiayoufang.com\",\n \"m.laoqu123.com\",\n \"m.lfdydk.com\",\n \"m.lovezhishou.com\",\n \"m.lusrg.cn\",\n \"m.lyjz001.com\",\n \"m.lzida.com\",\n \"m.lzytt.com\",\n \"m.maopuzw.com\",\n \"m.mgogo.com\",\n \"m.mgsue.cn\",\n \"m.miaoxinqipei.com\",\n \"m.mightiger.net\",\n \"m.miiuv.com\",\n \"m.miupp.com\",\n \"m.mmkvi.com\",\n \"m.mouaa.com\",\n \"m.mqgpo.com\",\n \"m.mrtuo.com\",\n \"m.mtuoa.com\",\n \"m.mushizhubao.com\",\n \"m.mxguan.com\",\n \"m.nduop.com\",\n \"m.neijh.com\",\n \"m.nejup.com\",\n \"m.nernv.com\",\n \"m.nfkos.com\",\n \"m.niegg.com\",\n \"m.nmtouzi.com\",\n \"m.nnfiy.com\",\n \"m.nouaa.com\",\n \"m.nthtcs.com\",\n \"m.ntxiangtai.com\",\n \"m.nuxyz.cn\",\n \"m.nwxzs.com\",\n \"m.nxypz.com\",\n \"m.oesnw.com\",\n \"m.opqsr.com\",\n \"m.osndy.com\",\n \"m.ourlj.com\",\n \"m.oyrim.com\",\n \"m.panda.voiceads.cn\",\n \"m.pbino.com\",\n \"m.phonthing.com\",\n \"m.picbr.com\",\n \"m.pieaa.com\",\n \"m.plerv.com\",\n \"m.pomkl.com\",\n \"m.poonscn.com\",\n \"m.pougg.com\",\n \"m.prazpf.cn\",\n \"m.pubbirdf.com\",\n \"m.puooi.com\",\n \"m.pwjhg.com\",\n \"m.pyerc.com\",\n \"m.qcw.com\",\n \"m.qhuik.com\",\n \"m.qianka.com\",\n \"m.qingzhencai.net\",\n \"m.qiyunmuye.com\",\n \"m.qsove.com\",\n \"m.qulishi.com\",\n \"m.qusub.com\",\n \"m.qvxyz.com\",\n \"m.rhcapass.com\",\n \"m.ricpt.com\",\n \"m.rmuqvq.cn\",\n \"m.rmwdn.com\",\n \"m.romgv.com\",\n \"m.rrsdl.com\",\n \"m.rwganw.cn\",\n \"m.sanitwealth.com\",\n \"m.sanjiangge.com\",\n \"m.sbenx.com\",\n \"m.sbinx.com\",\n \"m.sewxi.com\",\n \"m.shenyunkeji.com\",\n \"m.simba.taobao.com\",\n \"m.sjaidu.com\",\n \"m.sjuqc.com\",\n \"m.sjzhushou.com\",\n \"m.smsksx.com\",\n \"m.sosjyx.com\",\n \"m.srrux.com\",\n \"m.suehy.com\",\n \"m.sxxca.com\",\n \"m.symaa.cn\",\n \"m.symab.cn\",\n \"m.symac.cn\",\n \"m.symad.cn\",\n \"m.symag.cn\",\n \"m.symaj.cn\",\n \"m.szqifu.com\",\n \"m.tansuotv.com\",\n \"m.tcksbz888.com\",\n \"m.tiantianedu.net\",\n \"m.tiaopimiao.net\",\n \"m.tick0.com\",\n \"m.tiojk.com\",\n \"m.tuopp.com\",\n \"m.twldmx.com\",\n \"m.txtxr.com\",\n \"m.uc123.com\",\n \"m.uczzd.cn\",\n \"m.ueram.com\",\n \"m.uissm.com\",\n \"m.vaxyz.com\",\n \"m.vbaou.com\",\n \"m.vbieu.com\",\n \"m.vbinu.com\",\n \"m.verpt.com\",\n \"m.vichc.com\",\n \"m.vouky.com\",\n \"m.vpon.com\",\n \"m.vsxet.com\",\n \"m.wcjup.com\",\n \"m.weboser.com\",\n \"m.weixingshexiangji.net\",\n \"m.wervp.com\",\n \"m.wgewj.cn\",\n \"m.wikigifth.com\",\n \"m.wjhehaofc.com\",\n \"m.wkjhd.com\",\n \"m.wnxcg.com\",\n \"m.wonwg.com\",\n \"m.wooboo.com.cn\",\n \"m.wrating.com\",\n \"m.wshufa.com\",\n \"m.wsxxu.com\",\n \"m.wuqutu.com\",\n \"m.wxhh678.com\",\n \"m.xcy8.com\",\n \"m.xdkje.com\",\n \"m.xeihy.com\",\n \"m.xetvb.com\",\n \"m.xhaiu.com\",\n \"m.xiangchim0.com\",\n \"m.xikdn.com\",\n \"m.xingxd.com\",\n \"m.xkqpco.com\",\n \"m.xkqpco.com.com\",\n \"m.xlsschina15.net\",\n \"m.xmgysweb.com\",\n \"m.xpjis.com\",\n \"m.xxkio.com\",\n \"m.yalayi.com\",\n \"m.yangjingbang.net\",\n \"m.yicang8.com\",\n \"m.yingchengtou.com\",\n \"m.ynnke.com\",\n \"m.yoiur.com\",\n \"m.yooli.com\",\n \"m.youweiprint.com\",\n \"m.yoyi.com.cn\",\n \"m.ysdhe.com\",\n \"m.yuandajiayuan.com\",\n \"m.yuxyz.com\",\n \"m.ywbwsm.com\",\n \"m.yyeks.com\",\n \"m.yyjhf.com\",\n \"m.yzjlsb.com\",\n \"m.zabxb.com\",\n \"m.zaoss.com\",\n \"m.zeiaa.com\",\n \"m.zenffs.cn\",\n \"m.zenwq.com\",\n \"m.zhuyuanp.club\",\n \"m.zhuyuanp.shop\",\n \"m.zhuyuanp.top\",\n \"m.zkwsdf.com\",\n \"m.zougg.com\",\n \"m.zuopp.com\",\n \"m1.baidu.com\",\n \"m1.daumcdn.net\",\n \"m1.mgogo.com\",\n \"m1.xcy8.com\",\n \"m2.qinsx.cn\",\n \"m3bnqqqw.com\",\n \"m5.apk.67mo.com\",\n \"m9.xcdf.cn\",\n \"m9.xcy8.com\",\n \"ma.baidu.com\",\n \"ma1.meishij.net\",\n \"ma2.meishij.net\",\n \"maccms.tan5858.com\",\n \"mackeeper.com\",\n \"macplatform.wondershare.com\",\n \"mad.kuuad.com\",\n \"mad.m.maxthon.cn\",\n \"m-adash.m.taobao.com\",\n \"madhouse.cn\",\n \"madmini.com\",\n \"mads.amazon.com\",\n \"mads.aol.com\",\n \"mads.dailymail.co.uk\",\n \"madserving.com\",\n \"magicwindow.cn\",\n \"magnetic.t.domdex.com\",\n \"maibahe300cc.com\",\n \"main.exdynsrv.com\",\n \"main.exoclick.com\",\n \"mainbx.com\",\n \"maipinshangmao.com\",\n \"mairuan.cn\",\n \"mairuan.com\",\n \"mairuan.com.cn\",\n \"mairuan.net\",\n \"mairuanwang.com\",\n \"maisoncherry.com\",\n \"makeding.com\",\n \"malacca.inveno.com\",\n \"manage.wdfans.cn\",\n \"maomaotang.com\",\n \"map.dxpmedia.com\",\n \"map.media6degrees.com\",\n \"mapping.yoyi.com.cn\",\n \"market.178.com\",\n \"market.21cn.com\",\n \"market.52pk.com\",\n \"market.duowan.com\",\n \"marketgid.com\",\n \"marketing.888.com\",\n \"marketing.etouch.cn\",\n \"marketingsolutions.yahoo.com\",\n \"marketo.com\",\n \"marketo.net\",\n \"masdk.3g.qq.com\",\n \"maskbaby.com.cn\",\n \"mass.mall044.com\",\n \"master.wap.dphub.sandai.net\",\n \"match.adsby.bidtheatre.com\",\n \"match.c8.net.ua\",\n \"match.p4p.1688.com\",\n \"match.prod.bidr.io\",\n \"match.rundsp.com\",\n \"matching.targeterra.com\",\n \"material.istreamsche.com\",\n \"material.mtty.xin\",\n \"mathtag.com\",\n \"mathtype.cn\",\n \"maw.wnbfw.com\",\n \"maxwebsearch.com\",\n \"maysunmedia.com\",\n \"mb.hockeybuzz.com\",\n \"mb.yidianzixun.com\",\n \"mb.zam.com\",\n \"mbai.cn\",\n \"mbd.weathercn.com\",\n \"mbrowser.news.haosou.com\",\n \"mbrowser.news.so.com\",\n \"mbs.weathercn.com\",\n \"mc.yandex.ru\",\n \"mclick.simba.taobao.com\",\n \"mcore.vcgame.cn\",\n \"md.1drj.com\",\n \"md.he9630.com\",\n \"md.sh5e.com\",\n \"md0z4dh.com\",\n \"mdc.meitustat.com\",\n \"mdotm.com\",\n \"mdpjnppsbjv.bid\",\n \"mdrecv.app.cntvwb.cn\",\n \"me.afp.chinanews.com\",\n \"mealsandsteals.sandiego6.com\",\n \"me-cdn.effectivemeasure.net\",\n \"med.heyzap.com\",\n \"medal.blog.csdn.net\",\n \"media.2011.8684.com\",\n \"media.cheshi-img.com\",\n \"media.fastclick.net\",\n \"media.jointreport-switch.com\",\n \"media.tianjimedia.com\",\n \"media.trafficfactory.biz\",\n \"media.trafficjunky.net\",\n \"media8.cn\",\n \"mediamgr.ugo.com\",\n \"mediaplex.com\",\n \"mediapro.pro.cn\",\n \"media-static.jointreport-switch.com\",\n \"mediav.com\",\n \"medrx.telstra.com.au\",\n \"megajoy.com\",\n \"meimeidaren.com\",\n \"meiti1.net\",\n \"meitubeauty.meitudata.com\",\n \"meitumq.com\",\n \"menghuanzs.com\",\n \"mengmengdas.com\",\n \"mengyuanwei.com\",\n \"message.meitu.com\",\n \"metok.sys.miui.com\",\n \"metrics.cnn.com\",\n \"mfan.iclick.com.cn\",\n \"mfm.video.qq.com\",\n \"mfp.deliver.ifeng.com\",\n \"mfsr.lenovomm.com\",\n \"mg.5pk\",\n \"mg.games.sina.com.cn\",\n \"mg.yadro.ru\",\n \"mgid.com\",\n \"mgldzcls.com\",\n \"mgogo.com\",\n \"mgwcn.com\",\n \"mgwl668.com\",\n \"mhd.1391.com\",\n \"mhdpay.1391.com\",\n \"mhdtestks3.1391.com\",\n \"mhdufile.1391.com\",\n \"mhjk.1391.com\",\n \"mhuodong.elong.com\",\n \"miam4.cn\",\n \"miaobeichina.com\",\n \"miaozhen.com\",\n \"mibook-10006092.cos.myqcloud.com\",\n \"microad-cn.com\",\n \"mid.houyi.baofeng.net\",\n \"midas.rong360.com\",\n \"midinfo.baofeng.com\",\n \"mie99.net\",\n \"migc.g.mi.com\",\n \"migcreport.g.mi.com\",\n \"migrate.driveapi.micloud.xiaomi.net\",\n \"migu.kssws.ks-cdn.com\",\n \"mihui.com\",\n \"miidi.net\",\n \"mijifen.com\",\n \"milk.yesky.com.cn\",\n \"millennialmedia.com\",\n \"millwardbrownacsr.com\",\n \"mimg.126.net\",\n \"mimg.7791.com.cn\",\n \"mindmanager.cc\",\n \"mindmapper.cc\",\n \"minesage.com\",\n \"minfo.wps.cn\",\n \"mingxianshanghang.cn\",\n \"mingysh.com\",\n \"mini.cpc.sogou.com\",\n \"mini.eastday.com\",\n \"mini.hao123.com\",\n \"mini.jijiplayer.com\",\n \"mini2015.qq.com\",\n \"minidcsc.kugou.com\",\n \"minipage.2345.com\",\n \"minisite.vidown.cn\",\n \"minisplat.cn\",\n \"miniye.xjts.cn\",\n \"mip.yuelvxing.com\",\n \"mipcache.bdstatic.com\",\n \"mipujia.com\",\n \"mis.g.mi.com\",\n \"miui.hdfdm.com\",\n \"miui.hftaili.com\",\n \"mivideo.g.mi.com\",\n \"mj70.cn\",\n \"mjs.csyymp4.com\",\n \"mkitgfs.com\",\n \"mlb.did.ijinshan.com\",\n \"mlgrrqymdsyk.com\",\n \"mlnbike.com\",\n \"mlog.aipai.com\",\n \"mlog.hiido.com\",\n \"mlog.m1905.cn\",\n \"mlog.search.xiaomi.net\",\n \"mlt01.com\",\n \"mm.2436.cn\",\n \"mm.anqu.com\",\n \"mm.jgchq.com\",\n \"mm.moquanad.com\",\n \"mmcc.yxlady.com\",\n \"mmg.aty.cp45.ott.cibntv.net\",\n \"mmg.aty.snmsohu.aisee.tv\",\n \"mng-ads.com\",\n \"mnkan.com\",\n \"mnwan.com\",\n \"mnxtu.com\",\n \"mo.haloapps.cn\",\n \"mo.kugou.com\",\n \"mo.res.wpscdn.cn\",\n \"mo.test.haloapps.com\",\n \"moad.cn\",\n \"moatads.com\",\n \"mob.huimee.net\",\n \"mobad.ijinshan.com\",\n \"mobadme.jp\",\n \"mobclix.com\",\n \"mobfox.com\",\n \"mobgi.com\",\n \"mobilead.kuwo.cn\",\n \"mobileads.google.com\",\n \"mobileads.msn.com\",\n \"mobileapptracking.com\",\n \"mobiledissector.com\",\n \"mobilelog.kugou.com\",\n \"mobile-pubt.ele.me\",\n \"mobile-service.segment.com\",\n \"mobilityware.com\",\n \"mobiorg8.com\",\n \"mobisage.cn\",\n \"mobvista.com\",\n \"mohecm.com\",\n \"moka.inte.sogoucdn.com\",\n \"mon.xtgreat.com\",\n \"monero.how\",\n \"money.qz828.com\",\n \"monitor.uu.qq.com\",\n \"moodoocrv.com.cn\",\n \"moogos.com\",\n \"mookie1.com\",\n \"moons.66bhy.com\",\n \"moonwish.com.cn\",\n \"mopub.com\",\n \"moquanad.com\",\n \"moren-1252794300.file.myqcloud.com\",\n \"mosa86.com\",\n \"mostat.wps.cn\",\n \"motohelpr.com\",\n \"motu.p4p.sina.com.cn\",\n \"motu.pagechoice.net\",\n \"mou.niu.xunlei.com\",\n \"moupdate10332052.wps.cn\",\n \"moutaihotel.cn\",\n \"movie.miaiche.cn\",\n \"mpb1.iteye.com\",\n \"mpb2.iteye.com\",\n \"mpp.vindicosuite.com\",\n \"mpro.baidu.com\",\n \"mps.nbcuni.com\",\n \"mps.weekslw.com\",\n \"mpush.cn\",\n \"mpzw.com\",\n \"mqq.zgdmsj.cn\",\n \"mqqad.cs0309.html5.qq.com\",\n \"mqqad.html5.qq.com\",\n \"mqqadr.reader.qq.com\",\n \"mrelko.com\",\n \"mrksys.com\",\n \"ms.awqsaged.cn\",\n \"ms.cmcm.com\",\n \"ms.cnczjy.com\",\n \"ms.continuedsys.cn\",\n \"ms.ienkdaccessible.cn\",\n \"ms.ienkdaccessory.cn\",\n \"ms.jyhwt.cn\",\n \"ms.myyage.com\",\n \"ms.vipstatic.com\",\n \"msads.net\",\n \"mscimg.com\",\n \"msclick2.kuwo.cn\",\n \"msg.mobile.kugou.com\",\n \"msg.ptqy.gitv.tv\",\n \"msg.push.51y5.net\",\n \"mshow.fang.com\",\n \"msite.baidu.com\",\n \"msltzer.cn\",\n \"msn.wrating.com\",\n \"msnclick.wrating.com\",\n \"msphoneclick.kuwo.cn\",\n \"mssp.baidu.com\",\n \"mstat.zol.com.cn\",\n \"mstzym.com\",\n \"msypr.com\",\n \"mti.35kds.com\",\n \"mtj.baidu.com\",\n \"mtl.ttsqgs.com\",\n \"mtrace.qq.com\",\n \"mtty-cdn.mtty.xin\",\n \"mtxsk.com\",\n \"mubite.cn\",\n \"munchkin.marketo.net\",\n \"musik-mp3.info\",\n \"mvads.kugou.com\",\n \"mvip.zhuba8.com\",\n \"mwa.xingyimin.com\",\n \"mwlucuvbyrff.com\",\n \"mxmrt.com\",\n \"mxpnl.com\",\n \"mxvp-ad-config-prod-1.zenmxapps.com\",\n \"mxvp-feature-toggle-prod-1.zenmxapps.com\",\n \"my.mobfox.com\",\n \"my1fc.m.b5200.net\",\n \"my1fimg.m.b5200.net\",\n \"myad.toocle.com\",\n \"mycleanmymac.com\",\n \"mydas.mobi\",\n \"mydisplay.ctfile.com\",\n \"myjsym.zichenit.com\",\n \"mymm.zichenit.com\",\n \"mytanwan.com\",\n \"mytzdhz.cn\",\n \"myycrw.com\",\n \"myzk1.com\",\n \"myzwqwe12.com\",\n \"mzy2014.com\",\n \"n.a.mosenni.com\",\n \"n.ads3-adnow.com\",\n \"n.amoad.com\",\n \"n.cosbot.cn\",\n \"n.gemini.yahoo.com\",\n \"n.ma.social-touch.com\",\n \"n.wjr1x.cn\",\n \"n.yfi8.com\",\n \"n.zqqf0.cn\",\n \"na1r.services.adobe.com\",\n \"na2m-pr.licenses.adobe.com\",\n \"nai.cpxkvc.com\",\n \"namedq.com\",\n \"namemek.com\",\n \"naqigs.com\",\n \"nativeapp.toutiao.com\",\n \"nav.winasdaq.com\",\n \"navi.gd.chinamobile.com\",\n \"nbhxgjz.com\",\n \"nbjjd.com\",\n \"nbzq.net\",\n \"nc004x.corp.youdao.com\",\n \"nc045x.corp.youdao.com\",\n \"ncachear.com\",\n \"nch.xnghmc.com\",\n \"nchte.com\",\n \"nclog.mars.baofeng.net\",\n \"nclog.pad.baofeng.net\",\n \"ncoyqc.com\",\n \"ndtzx.com\",\n \"ndy.code.weddingeeos.com\",\n \"ne.1rtb.com\",\n \"ne9377.com\",\n \"neirong.baidu.com\",\n \"nend.net\",\n \"nest.youwatch.org\",\n \"net.rayjump.com\",\n \"netko0o.com\",\n \"netshelter.net\",\n \"netspidermm.indiatimes.com\",\n \"network.aufeminin.com\",\n \"network.business.com\",\n \"network.sofeminine.co.uk\",\n \"networkbench.com\",\n \"new.ltheanine.cn\",\n \"new.yokaunion.com\",\n \"new.zhqiu.com\",\n \"newapi.com\",\n \"newrelic.com\",\n \"news.51y5.net\",\n \"news.58.com\",\n \"news.cxxtv.com\",\n \"news.mpush.qq.com\",\n \"news.push.126.net\",\n \"news.s9377.com\",\n \"news.xueyanshan.com\",\n \"news-img.51y5.net\",\n \"news-l.play.aiseet.atianqi.com\",\n \"news-l.play.cp81.ott.cibntv.net\",\n \"news-l.play.ott.video.qq.com\",\n \"news-log.51y5.net\",\n \"newspage.xilu.com\",\n \"newspush.sinajs.cn\",\n \"newswifiapi.dfshurufa.com\",\n \"newton-api.ele.me\",\n \"nex.163.com\",\n \"nexage.com\",\n \"nexstep.zdworks.com\",\n \"nextcps.com\",\n \"nextlnk9.com\",\n \"nexus.ensighten.com\",\n \"nfh.cnshef.com\",\n \"ngads.go.com\",\n \"nicelabel.cc\",\n \"ninebox.cn\",\n \"ninemsn.imrworldwide.com\",\n \"niurenw.com\",\n \"niux88.com\",\n \"niuxgame77.com\",\n \"niwd.zhybw88.com\",\n \"njdijiani.com\",\n \"njfsk.com\",\n \"njmpacc.com\",\n \"njq.net\",\n \"njs.imagicskin.com\",\n \"njs.myyage.com\",\n \"njs.reliancevalve.com\",\n \"njxczy.com\",\n \"nkeo.top\",\n \"nlog.baidu.com\",\n \"nmbtedu.com\",\n \"nmkgs.cn\",\n \"nmpcdn.com\",\n \"nmqbg.com\",\n \"nnedbx.com\",\n \"nngft.com\",\n \"noberlmall.com\",\n \"nongsalei.com\",\n \"nop.xpanama.net\",\n \"notice.game.xiaomi.com\",\n \"notice.uchome.manyou.com\",\n \"notifiter.youmi.net\",\n \"notify.oupeng.com\",\n \"novelsns.html5.qq.com\",\n \"nowskip.com\",\n \"npdaqy6x1j.me\",\n \"nr1234.com\",\n \"nryiou.cn\",\n \"nsclickvideo.baidu.com\",\n \"nsnmiaomu.cn\",\n \"nsy.hnzyfs.com\",\n \"nt.phpwind.com\",\n \"ntalker.com\",\n \"nterbx.com\",\n \"ntfsformac.cc\",\n \"ntfsformac.cn\",\n \"nthyn.com\",\n \"ntx.quanliyouxi.cn\",\n \"nv.souid.com\",\n \"nvrentao8.com\",\n \"nvshenfan.com\",\n \"nwejs.alcryp.com\",\n \"nwejs.myzcoffice.com\",\n \"nwwap.com\",\n \"nxrhs.com\",\n \"nxrxt.con\",\n \"ny7f6goy.bid\",\n \"nylalobghyhirgh.com\",\n \"nysita.com\",\n \"nzezn.com\",\n \"o.08jm.cn\",\n \"o.if.qidian.com\",\n \"o.minisplat.cn\",\n \"o091i.com\",\n \"o2o.api.xiaomi.com\",\n \"o2omobi.com\",\n \"o7xs6runw.bkt.clouddn.com\",\n \"oa129.com\",\n \"oadz.com\",\n \"oa-panther.data.aliyun.com\",\n \"oas.autotrader.co.uk\",\n \"oas.luxweb.com\",\n \"oas.skyscanner.net\",\n \"oasc07.citywire.co.uk\",\n \"oascentral.abclocal.go.com\",\n \"oascentral.chron.com\",\n \"oascentral.hosted.ap.org\",\n \"oascentral.lycos.com\",\n \"oascentral.newsmax.com\",\n \"oascentral.sina.com\",\n \"oascentral.sina.com.hk\",\n \"oask.xulizui6.com\",\n \"obeyter.com\",\n \"ocbv0.baiyangzs.com\",\n \"odc.starwave.com\",\n \"odin.goo.mx\",\n \"officeme.cn\",\n \"offline-adv.oray.com\",\n \"oikxlcv.wang\",\n \"oimagea2.ydstatic.com\",\n \"ojngisbfwwyp.com\",\n \"ok.432kkk.com\",\n \"ok365.com\",\n \"okkkk.com\",\n \"okm918.com\",\n \"okokw.com\",\n \"olcdn.com\",\n \"olpv.onlylady.com\",\n \"olpvimg.onlylady.com\",\n \"olstats.onlylady.com\",\n \"omega7o.com\",\n \"omg.inte.sogoucdn.com\",\n \"omnikool.discovery.com\",\n \"omtrdc.net\",\n \"on.maxspeedcdn.com\",\n \"onclickads.net\",\n \"onclicktop.com\",\n \"onclkds.com\",\n \"one.520319.cn\",\n \"onepush.query.yahoo.com\",\n \"onesoft.im\",\n \"onetad.com\",\n \"onetag-sys.com\",\n \"onewhee.com\",\n \"onlifjj.net\",\n \"onlinetips.baofeng5.baofeng.net\",\n \"oomyv.com\",\n \"ooniu.com\",\n \"ooss.oss.aliyuncs.com\",\n \"op00w.baiyangzs.com\",\n \"open.play.cn\",\n \"openapi-news.meizu.com\",\n \"openrcv.baidu.com\",\n \"openstat.net\",\n \"openstorage.ad.cmvideo.cn\",\n \"opgirl-tmp.adbxb.cn\",\n \"oppo.yidianzixun.com\",\n \"optaim.com\",\n \"optimix.asia\",\n \"optimix.cn\",\n \"optimized-by.rubiconproject.com\",\n \"optimizelyapis.com\",\n \"oq68.com\",\n \"orchidscape.net\",\n \"oredero.com\",\n \"orz.hupu.com\",\n \"osc.uranus.sogou.com\",\n \"osfota.cdn.aliyun.com\",\n \"oss-asq-static.11222.cn\",\n \"otf.msn.com\",\n \"oth.eve.mdt.qq.com\",\n \"oth.str.mdt.qq.com\",\n \"oth.update.mdt.qq.com\",\n \"otheve.play.aiseet.atianqi.com\",\n \"othstr.play.aiseet.atianqi.com\",\n \"ou188.com\",\n \"output.nend.net\",\n \"overture.com\",\n \"overturechina.com\",\n \"ow.biqugego.com\",\n \"ow.s1.shuhuangge.org\",\n \"ow.s2.shuhuangge.org\",\n \"owin.biqugego.com\",\n \"ox.furaffinity.net\",\n \"oyzsverimywg.com\",\n \"p.7060.la\",\n \"p.99mssj.com\",\n \"p.abcache.com\",\n \"p.bdjiazanmiaomu.com\",\n \"p.bjdianyue.com\",\n \"p.bnuni.com\",\n \"p.clkservice.youdao.com\",\n \"p.ecwan77.net\",\n \"p.inte.sogou.com\",\n \"p.kf3msfm.com\",\n \"p.kjwx8.com\",\n \"p.kugou.com\",\n \"p.m5bn.com\",\n \"p.mendoc.cn\",\n \"p.niudashu.com\",\n \"p.qiailm.com\",\n \"p.qijijs.top\",\n \"p.raidmedia.com.cn\",\n \"p.rfihub.com\",\n \"p.saozhu1.top\",\n \"p.sdu8cvc.com\",\n \"p.shagent.com\",\n \"p.skimresources.com\",\n \"p.szonline.net\",\n \"p.tamenshuo.com\",\n \"p.tencentmind.com\",\n \"p.twitter.com\",\n \"p.vq6nsu.cn\",\n \"p.yizuya.com\",\n \"p.ynjczy.net\",\n \"p0y.cn\",\n \"p1.18zhongyao.com\",\n \"p1.qinsx.cn\",\n \"p2.hyz86.com\",\n \"p2.qinsx.cn\",\n \"p2.ykauto.cn\",\n \"p215223.clksite.com\",\n \"p215223.inclk.com\",\n \"p215223.mycdn2.co\",\n \"p2pmid.baofeng.com\",\n \"p3p.sogou.com\",\n \"p3p.yahoo.com\",\n \"p3tt.com\",\n \"p4p.sina.com.cn\",\n \"p4psearch.china.alibaba.com\",\n \"p555.cc\",\n \"p8u.hinet.net\",\n \"package01.com\",\n \"pad.zhywyl.cn\",\n \"padsdel2.cdnads.com\",\n \"page.acm.dzwww.com\",\n \"page.xywy.com\",\n \"pagead.google.com\",\n \"pagead.l.google.com\",\n \"pagead-tpc.l.google.com\",\n \"pagechoice.com\",\n \"pagechoice.net\",\n \"pagechoicemotu.gentags.net\",\n \"pages2.marketo.com\",\n \"paimgcdn.baidu.com\",\n \"painiuimg.com\",\n \"palmnews.sina.cn\",\n \"panda.kdnet.net\",\n \"pangu.cc\",\n \"panoramio.com\",\n \"papajia55.com\",\n \"parking.zunmi.cn\",\n \"parser.houyi.baofeng.net\",\n \"partner.bargaindomains.com\",\n \"partner.catchy.com\",\n \"partner.premiumdomains.com\",\n \"partner.toutiao.com\",\n \"partners.fshealth.com\",\n \"partners.keezmovies.com\",\n \"partners.optiontide.com\",\n \"partners.pornerbros.com\",\n \"partners.rochen.com\",\n \"partners.sportingbet.com.au\",\n \"partners.vouchedfor.co.uk\",\n \"partners.xpertmarket.com\",\n \"party-nngvitbizn.now.sh\",\n \"pasco.cc\",\n \"pass1.soogif.com\",\n \"pass2.soogif.com\",\n \"passwordrecovery.cn\",\n \"passwz.com\",\n \"pat.farvd.com\",\n \"patriot.cs.pp.cn\",\n \"pay.holaq.com\",\n \"pay.mobile.sina.cn\",\n \"pay838.com\",\n \"pb.funshion.net.cn\",\n \"pb.s3wfg.com\",\n \"pb.sogou.com\",\n \"pb.sys.pp8.com\",\n \"pb.wang502.com\",\n \"pb3.pstatp.com\",\n \"pbd.sogou.com\",\n \"pbs.lenovomm.com\",\n \"pc.107788.com\",\n \"pc.5151gj.com\",\n \"pc.ctsywy.com\",\n \"pc.quansj.cn\",\n \"pc.videoclick.baidu.com\",\n \"pcauto.irs01.com\",\n \"pcbrowser.dd.qq.com\",\n \"pcfg.wps.cn\",\n \"pclog.dftoutiao.com\",\n \"pclog.suishenyun.net\",\n \"pcmzn.com\",\n \"pcsoftwords.dftoutiao.com\",\n \"pcxzo.pluto.sogou.com\",\n \"pd7-imp.revsci.net\",\n \"pdfexpert.cc\",\n \"pdl.gionee.com\",\n \"pdsjycm.com\",\n \"pear.dleke.com\",\n \"pedailyu.com\",\n \"pee.cn\",\n \"pegasus.cmcm.com\",\n \"pei-ads.playboy.com\",\n \"pf.h5game.cn\",\n \"pf.pchome.net\",\n \"pf-2.pchome.net\",\n \"pfp.sina.com.cn\",\n \"pfpip.sina.com\",\n \"pgdt.gtimg.cn\",\n \"pgdt.ugdtimg.com\",\n \"photo.dhford.cn\",\n \"photo.lyghjzs.cn\",\n \"photo.qianerbai.cn\",\n \"photo.shyexiang.cn\",\n \"photo.welldex.cn\",\n \"photo.xunhuaji.cn\",\n \"photo.zhanhevr.cn\",\n \"phpad.cqnews.net\",\n \"pic.0597kk.com\",\n \"pic.14bobo.com\",\n \"pic.2u.com.cn\",\n \"pic.adver.com.tw\",\n \"pic.aihaogou.com.cn\",\n \"pic.by175.com\",\n \"pic.casee.cn\",\n \"pic.cnmo-img.com.cn\",\n \"pic.dotmore.com.tw\",\n \"pic.ea3w.com\",\n \"pic.eduancm.com\",\n \"pic.fengniao.com\",\n \"pic.haowj.com.cn\",\n \"pic.jdbbs.com\",\n \"pic.jd-bbs.com\",\n \"pic.jdunion.com\",\n \"pic.moad.cn\",\n \"pic.neiyicun.net\",\n \"pic.new400.cn\",\n \"pic.pic-img.com\",\n \"pic.punchbox.org\",\n \"pic.pxstda.com\",\n \"pic.usingde.com\",\n \"pic.zol-img.com.cn\",\n \"pic1.59wd.com\",\n \"pic1.onetad.com\",\n \"pic183025.images9999.com\",\n \"pic2.onetad.com\",\n \"pic2016.5442.com\",\n \"pic2016.ytqmx.com\",\n \"pic3.onetad.com\",\n \"pic494036.images9999.com\",\n \"pic8.onetad.com\",\n \"pic837013.images9999.com\",\n \"picsinfog.com\",\n \"picture.duokan.com\",\n \"picturesquefilms.net\",\n \"pikacn.com\",\n \"pimg1.126.net\",\n \"ping.acc.sogou.com\",\n \"ping.chartbeat.net\",\n \"ping.pinyin.sogou.com\",\n \"ping.weiduofan.com\",\n \"pingbi.diudou.com\",\n \"pingdom.net\",\n \"pingma.qq.com\",\n \"pingshetrip.com\",\n \"pintour.com\",\n \"pinzhitmall.com\",\n \"pix.impdesk.com\",\n \"pix.tagcdn.com\",\n \"pix04.revsci.net\",\n \"pixel.adsafeprotected.com\",\n \"pixel.mathtag.com\",\n \"pixel.quantserve.com\",\n \"pixel.rubiconproject.com\",\n \"pixel.tapad.com\",\n \"pixel.vihub.ru\",\n \"pixel.wp.com\",\n \"pixel-hk.pixelinteractivemedia.com\",\n \"pixels.asia\",\n \"pixfuture.net\",\n \"pj3456.com\",\n \"pj39330.com\",\n \"pj50.com\",\n \"pj5189.com\",\n \"pj550077.com\",\n \"pjbjzf.com\",\n \"pjogndc8ixoidna.360doc.cn\",\n \"pjtymy.cn\",\n \"pjyu.golden1.sogou.com\",\n \"pk840.com\",\n \"p-l.play.aiseet.atianqi.com\",\n \"pl108258.puserving.com\",\n \"pl14369502.puserving.com\",\n \"platform.wondershare.com\",\n \"playad.xjmg.com\",\n \"player.1800coupon.com\",\n \"player.1stcreditrepairs.com\",\n \"player.800directories.com\",\n \"player.accoona.com\",\n \"player.alloutwedding.com\",\n \"player.insuranceandhealth.com\",\n \"playinfo.gomlab.com\",\n \"plista.com\",\n \"plmkolp.m.58xs.tw\",\n \"plt.data.pplive.com\",\n \"plwan.com\",\n \"plz.jandan.net\",\n \"pm.sdaiv.com\",\n \"pmir.3g.qq.com\",\n \"pmm.people.com.cn\",\n \"pmptrack-autohome.gentags.net\",\n \"pmptrack-letv.gentags.net\",\n \"pmptrack-yidianzixunxm.gentags.net\",\n \"pmptrack-youku.gentags.net\",\n \"png.lu.sogoucdn.com\",\n \"pnhfc.com\",\n \"pofang.com\",\n \"polkoa.com\",\n \"pomhz.com\",\n \"pop.91mangrandi.com\",\n \"pop.code.mytanwan.com\",\n \"pop.code.poyang.cn\",\n \"pop.sjk.ijinshan.com\",\n \"popads.net\",\n \"popme.163.com\",\n \"poppyta.com\",\n \"popup.jointreport-switch.com\",\n \"popup.msn.com\",\n \"popupad.cn\",\n \"post.ra.icast.cn\",\n \"poster.weather.com.cn\",\n \"powergg.top\",\n \"poyang.com\",\n \"pp.sxjkc.cn\",\n \"pp2.dhzw.org\",\n \"pp9899.com\",\n \"ppjia55.com\",\n \"ppoi.org\",\n \"ppurifier.game.xiaomi.com\",\n \"ppx.hgo7r.cn\",\n \"pr.atwola.com\",\n \"pr.ybp.yahoo.com\",\n \"pr00001.com\",\n \"practivate.adobe.com\",\n \"pr-bh.ybp.yahoo.com\",\n \"prc.rjje4.com\",\n \"prcappzone.intel.com\",\n \"pre.api.tw06.xlmc.sandai.net\",\n \"pre.ra.icast.cn\",\n \"prerollads.ign.com\",\n \"priceinfo.comuv.com\",\n \"pro.cn\",\n \"pro.heiguang.com\",\n \"pro.iweihai.cn\",\n \"probes.cedexis.com\",\n \"profile.ssp.rambler.ru\",\n \"projectwonderful.com\",\n \"prom.gome.com.cn\",\n \"promo.fileforum.com\",\n \"promos.fling.com\",\n \"promote.biz.weibo.cn\",\n \"promote.caixin.com\",\n \"promote.pair.com\",\n \"promotion.aliyun.com\",\n \"promotion.gomlab.com\",\n \"promotions.iasbet.com\",\n \"propellerads.com\",\n \"prophet.heise.de\",\n \"proton.flurry.com\",\n \"proxy.sec.miui.com\",\n \"prw.lenovomm.com\",\n \"ps.3fenge.com\",\n \"psb.lenovomm.com\",\n \"psfq.gou.sogou.com\",\n \"psma02.com\",\n \"ptdrw.com\",\n \"ptkhy.com\",\n \"ptw.la\",\n \"pub.betclick.com\",\n \"pub.chinadailyasia.com\",\n \"pub.funshion.com\",\n \"pub.mop.com\",\n \"pub1.cope.es\",\n \"pubbirdf.com\",\n \"public6.com\",\n \"publicidad.net\",\n \"publicidad.tv\",\n \"publish.ad.youth.cn\",\n \"pubmatic.com\",\n \"pubnative.net\",\n \"pubnub.com\",\n \"pubs.hiddennetwork.com\",\n \"puds.test.uae.uc.cn\",\n \"puds.ucweb.com\",\n \"pull.push.sogou.com\",\n \"punchbox.org\",\n \"punuomisi.cn\",\n \"pups.bdimg.com\",\n \"pupu.xnhh120.com\",\n \"push.126.net\",\n \"push.5z5zw.com\",\n \"push.air-matters.com\",\n \"push.com2us.net\",\n \"push.feng.com\",\n \"push.mobile.kugou.com\",\n \"push.res.meizu.com\",\n \"push.wandoujia.com\",\n \"push.wapx.cn\",\n \"push.yuedu.163.com\",\n \"push.zdworks.com\",\n \"push.zhangyue.com\",\n \"push.zhanzhang.baidu.com\",\n \"push-android.myzaker.com\",\n \"pushapi.lenovomm.com\",\n \"push-dc.51y5.net\",\n \"pv.anzhi.com\",\n \"pv.cheshi.com\",\n \"pv.enet.com.cn\",\n \"pv.focus.cn\",\n \"pv.ra.icast.cn\",\n \"pv.sogou.com\",\n \"pv.xcar.com.cn\",\n \"pv.zdnet.com.cn\",\n \"pv.zol.com.cn\",\n \"pvc.zol.com.cn\",\n \"pvdata.ku6.com\",\n \"pvlog.hd.baofeng.com\",\n \"pvlog.moviebox.baofeng.net\",\n \"pvm.zol.com.cn\",\n \"pvmsite.zol.com.cn\",\n \"pvsite.zol.com.cn\",\n \"pvstat.html5.qq.com\",\n \"pvtest.zol.com.cn\",\n \"pwj.biqugezw.com\",\n \"px.adhigh.net\",\n \"px.media-serving.com\",\n \"px.moatads.com\",\n \"px.owneriq.net\",\n \"px.powerlinks.com\",\n \"px.steelhousemedia.com\",\n \"pxene.com\",\n \"pxl.connexity.net\",\n \"py.qlogo.cn\",\n \"py.wikigifth.com\",\n \"py2.qlogo.cn\",\n \"pyerc.com\",\n \"pyzkk.com\",\n \"q.ox11.com\",\n \"q.s.cr-nielsen.com\",\n \"q1scv.vov0.com\",\n \"q6rwa.eschangchi.com\",\n \"qbyy010.com\",\n \"qchannel01.cn\",\n \"qchannel02.cn\",\n \"qchannel03.cn\",\n \"qchannel04.cn\",\n \"qcjslm.com\",\n \"qcl777.com\",\n \"qd.dhzw.org\",\n \"qd.js.sanjiangge.com\",\n \"qd.moutaihotel.cn\",\n \"qd.wanjuanba.com\",\n \"qd.x4399.com\",\n \"qdchunyu.com\",\n \"qeoa.hawbfa.com\",\n \"qgss8.com\",\n \"qhaif.com\",\n \"qhl.bealge.sogou.com\",\n \"qiailm.com\",\n \"qianclick.baidu.com\",\n \"qiaopiguniang.com\",\n \"qichexin.com\",\n \"qihaoqu.com\",\n \"qinchugudao.com\",\n \"qingqu.la\",\n \"qiqipower.com\",\n \"qiqivv.com\",\n \"qiqiww.com\",\n \"qiqiyii.com\",\n \"qiye11.ejunshi.net\",\n \"qiyem.ejunshi.com\",\n \"qiyezs.ejunshi.com\",\n \"qiyou.com\",\n \"qjfcdn1220.0101122.com\",\n \"qjjtc.com\",\n \"qlisv.siemens6es7.com\",\n \"qlmho.renhengshangmao.com\",\n \"qloer.com\",\n \"qlonglong.com\",\n \"qmkdy.com\",\n \"qoiusky.com\",\n \"qooic.com\",\n \"qp.yunanfuwuqi.com\",\n \"qq.guansenff.cn\",\n \"qq.irs01.com\",\n \"qq.tapiche.cn\",\n \"qq2.co\",\n \"qq61.com\",\n \"qqhuhu.com\",\n \"qqm98.com\",\n \"qqshow2-item.qq.com\",\n \"qqx.cqqytgpt.com\",\n \"qqzu.com\",\n \"qsbz2011.com\",\n \"qshxc.com\",\n \"qt.biqugezw.com\",\n \"qt002x.corp.youdao.com\",\n \"qtmojo.cn\",\n \"qtmojo.com\",\n \"quanliyouxi.cn\",\n \"quansj.cn\",\n \"quantcount.com\",\n \"quantserve.com\",\n \"qucaigg.com\",\n \"queene.cn\",\n \"questionmarket.com\",\n \"qujishu.com\",\n \"qumi.com\",\n \"qupinhj.com\",\n \"qutaobi.com\",\n \"quw18.com\",\n \"quyaoya.com\",\n \"qweqwe.mctvhp.cn\",\n \"qxjdlf.com\",\n \"qxm.pluto.sogou.com\",\n \"qxxys.com\",\n \"qyctj.com\",\n \"qytyf.com\",\n \"qzdag.com\",\n \"qzdfc.com\",\n \"qzgjprj.com\",\n \"qzkxt.com\",\n \"r.0.0.0.0.cn\",\n \"r.254a.com\",\n \"r.5207470.com\",\n \"r.browser.miui.com\",\n \"r.bxb.oupeng.com\",\n \"r.dmp.sina.com.cn\",\n \"r.mail.163.com\",\n \"r.msn.com\",\n \"r.myadx.net\",\n \"r.ow.0.0.0.0.cn\",\n \"r.pixgold.com\",\n \"r.radikal.ru\",\n \"r.xcycm.com\",\n \"r.youmi.net\",\n \"r.zlongad.com\",\n \"r8nu86wg.me\",\n \"ra.gtimg.com\",\n \"rabbit.meitustat.com\",\n \"rabbit.tg.meitu.com\",\n \"rack.bauermedia.co.uk\",\n \"rad.live.com\",\n \"rad.microsoft.com\",\n \"rad.msn.com\",\n \"rad.reporo.net\",\n \"radar.cedexis.com\",\n \"raeqqe.cn\",\n \"rank.hit.china.com\",\n \"rannabio.com\",\n \"ratings.lycos.com\",\n \"raw.okwan.cn\",\n \"rayjump.com\",\n \"rbp.emea.mxptint.net\",\n \"rbp.mxptint.net\",\n \"rbs.haiyunx.com\",\n \"rbywg.com\",\n \"rc.fthcz.com\",\n \"rc.haodongkeji.cn\",\n \"rc.mgwcn.com\",\n \"rc.xmcmn.com\",\n \"rc2waycm-atl.netmng.com\",\n \"rc-au.imrworldwide.com\",\n \"rcmd.pop.ijinshan.com\",\n \"rcp.c.appier.net\",\n \"rcv.iclicash.com\",\n \"rcv.jesgoo.com\",\n \"rcv.mobad.ijinshan.com\",\n \"rcv.moogos.com\",\n \"rcv.union-wifi.com\",\n \"rcyy3.kaopuwangjz.com\",\n \"rd.ane.yahoo.co.jp\",\n \"rd.e.sogou.com\",\n \"rdiqt.cn\",\n \"rdtuijian.com\",\n \"re.m.taobao.com\",\n \"re.taobao.com\",\n \"re.taotaosou.com\",\n \"reachmax.cn\",\n \"reader.browser.miui.com\",\n \"reader.meizu.com\",\n \"reader.res.meizu.com\",\n \"realtime.monitor.ppweb.com.cn\",\n \"rec.g.163.com\",\n \"rec.moviebox.baofeng.net\",\n \"recreativ.ru\",\n \"recv-vd.gridsumdissector.cn\",\n \"recv-vd.gridsumdissector.com\",\n \"recv-wd.gridsumdissector.com\",\n \"red.bayimg.net\",\n \"redirect.simba.taobao.com\",\n \"redpaper-10006092.cos.myqcloud.com\",\n \"redvase.bravenet.com\",\n \"referrer.disqus.com\",\n \"relap.io\",\n \"release.baidu.com\",\n \"reliancevalve.com\",\n \"remote88.com\",\n \"remotedu.cn\",\n \"rem-track.bild.de\",\n \"rencai56.com\",\n \"renren2.maoyun.tv\",\n \"req.startappservice.com\",\n \"res.cocounion.com\",\n \"res.dxpmedia.com\",\n \"res.icast.cn\",\n \"res.ipingke.com\",\n \"res.qhupdate.com\",\n \"res3.feedsportal.com\",\n \"rescn.u3.ucweb.com\",\n \"resetgey.com\",\n \"res-ga.smzdm.com\",\n \"resolver.gslb.mi-idc.com\",\n \"resolver.msg.xiaomi.net\",\n \"resource.baomihua.com\",\n \"responsys.net\",\n \"ret.xinlongrubber.com\",\n \"rev.fapdu.com\",\n \"revdepo.com\",\n \"revealads.appspot.com\",\n \"revsci.net\",\n \"rfir2.50w.me\",\n \"rh.code.jjyx.com\",\n \"rh.greenbetterkids.com\",\n \"rhgyg.com\",\n \"rich.kuwo.cn\",\n \"richmedia.yimg.com\",\n \"riqu2015.com\",\n \"river.zhidao.baidu.com\",\n \"rj.baidu.com\",\n \"rjgw.theta.sogou.com\",\n \"rjs.niuxgame77.com\",\n \"rk.rongchengxxw.com\",\n \"rlcdn.com\",\n \"rlogs.youdao.com\",\n \"rm.ra.icast.cn\",\n \"rm.sina.com.cn\",\n \"rmads.eu.msn.com\",\n \"rmads.msn.com\",\n \"rmcxw.cn\",\n \"rmoeu.mercury.sogou.com\",\n \"rmtx.ra.icast.cn\",\n \"rmw.jdburl.com\",\n \"rnfrfxqztlno.com\",\n \"roia.com\",\n \"rosi.okkkk.com\",\n \"rotabanner.kulichki.net\",\n \"rotate.ymtracking.com\",\n \"rotator.tradetracker.net\",\n \"router.bittorrent.com\",\n \"rovio-news-app.angrybirdsgame.com\",\n \"rp.crasheye.cn\",\n \"rp.gwallet.com\",\n \"rpaulfrank.com\",\n \"rpc-php.trafficfactory.biz\",\n \"rplog.baidu.com\",\n \"rpnews.itaoxiaoshuo.com\",\n \"rpt.anchorfree.net\",\n \"rqgsf.com\",\n \"rr.knet.cn\",\n \"rrr.youle55.com\",\n \"rrsubway.com\",\n \"rs.sinajs.cn\",\n \"rs1.rensheng5.com\",\n \"rsas.szzek.com\",\n \"rsccs.com\",\n \"rt.funshion.net\",\n \"rt.gsspat.jp\",\n \"rtas.videocc.net\",\n \"rtax.criteo.com\",\n \"rtb.com.ru\",\n \"rtb.eanalyzer.de\",\n \"rtb.metrigo.com\",\n \"rtbasia.com\",\n \"rtb-p.kejet.net\",\n \"rtbstat.zcdsp.com\",\n \"rtlog.vidown.cn\",\n \"rtmonitor.kugou.com\",\n \"rto.steelhousemedia.com\",\n \"ruan88.com\",\n \"rubicon-match.dotomi.com\",\n \"rubiconproject.com\",\n \"rudy.adsnative.com\",\n \"ru-gmtdmp.mookie1.com\",\n \"rum-collector.pingdom.net\",\n \"rum-static.pingdom.net\",\n \"runetki.joyreactor.ru\",\n \"runiman.com\",\n \"rutrk.org\",\n \"ruxianke.com\",\n \"rvb.quanliyouxi.cn\",\n \"rwjfs.com\",\n \"rwq.youle55.com\",\n \"rxwan.com\",\n \"ry51w.cn\",\n \"s.0.0.0.0.cn\",\n \"s.051352.com\",\n \"s.0594529.com\",\n \"s.17173cdn.com\",\n \"s.35kds.com\",\n \"s.5jjx.net\",\n \"s.652748.com\",\n \"s.6travel.com\",\n \"s.abcache.com\",\n \"s.alitui.weibo.com\",\n \"s.baidu.com\",\n \"s.bmgan.com\",\n \"s.caduka.cn\",\n \"s.cdn.u17t.com\",\n \"s.cdxyb.cn\",\n \"s.clkservice.youdao.com\",\n \"s.com2us.net\",\n \"s.coveredsys.cn\",\n \"s.cr-nielsen.com\",\n \"s.csbew.com\",\n \"s.ddstu.com\",\n \"s.de123.net\",\n \"s.doyo.cn\",\n \"s.dpcq1.net\",\n \"s.dsjcfw.com\",\n \"s.effectivemeasure.net\",\n \"s.ekeide.com\",\n \"s.georgias.cn\",\n \"s.go.sohu.com\",\n \"s.haiyunx.com\",\n \"s.hk9600.com\",\n \"s.hkfuy.com\",\n \"s.hnhgw.cn\",\n \"s.hzht666.com\",\n \"s.img.mix.sina.com.cn\",\n \"s.iroby.com\",\n \"s.iuuff.com\",\n \"s.jandan.com\",\n \"s.jimdo.com\",\n \"s.jlminte.com\",\n \"s.jpush.cn\",\n \"s.jzkelida.com\",\n \"s.khgj.cn\",\n \"s.l8l9.com\",\n \"s.maipubao.cn\",\n \"s.meimeidaren.com\",\n \"s.mgwcn.com\",\n \"s.mt145.com\",\n \"s.okmgy.cn\",\n \"s.phpwind.com\",\n \"s.qd.qingting.fm\",\n \"s.qd.qingtingfm.com\",\n \"s.qhupdate.com\",\n \"s.qtad.qingting.fm\",\n \"s.qzkxt.com\",\n \"s.ryre.cn\",\n \"s.sh.qihoo.com\",\n \"s.shiftrro.com\",\n \"s.staqnet.com\",\n \"s.temaidi.com\",\n \"s.trafficjam.cn\",\n \"s.uc627.com\",\n \"s.uuidksinc.net\",\n \"s.wapadv.com\",\n \"s.wrating.com\",\n \"s.wxktv.cn\",\n \"s.x.cn.xtgreat.com\",\n \"s.xcfe.cn\",\n \"s.xinghao89.com\",\n \"s.xmcmn.com\",\n \"s.yanpoly.com\",\n \"s.yfycy.com\",\n \"s.yidianzixun.com\",\n \"s.yjkyj.cn\",\n \"s.youmi.net\",\n \"s.ysxufeng.com\",\n \"s.yunpifu.cn\",\n \"s.zgclmw.cn\",\n \"s.zixuntop.com\",\n \"s.zjhoudao.com\",\n \"s.zlongad.com\",\n \"s.zxwdw.com\",\n \"s0.2mdn.net\",\n \"s03.optimix.asia\",\n \"s1.2mdn.net\",\n \"s1.cmfu.com\",\n \"s1.hiapk.com\",\n \"s1.hnhbyxdq.com\",\n \"s1.huiqituan.com\",\n \"s1.iigushi.com\",\n \"s1.kutongji.com\",\n \"s1.mingmingtehui.com\",\n \"s1.qiqutt.cn\",\n \"s1.qiqutt.com\",\n \"s1.qiuyi.cn\",\n \"s1.s8tu.com\",\n \"s1.tansuotv.com\",\n \"s10.histats.com\",\n \"s2.dnaxddnc.com\",\n \"s2.hiapk.com\",\n \"s2.huoying666.com\",\n \"s2.kuaibaopay.com\",\n \"s2.mingmingtehui.com\",\n \"s2.yandui.com\",\n \"s2.zdface.com\",\n \"s2.zdmimg.com\",\n \"s3.pfp.sina.net\",\n \"s3.rongnews.com\",\n \"s3d4.cn\",\n \"s4.55.la\",\n \"s4.histats.com\",\n \"s400cc.com\",\n \"s5.keydot.net\",\n \"s8.001fzc.com\",\n \"s8.dnaxddnc.com\",\n \"s8x1.com\",\n \"s9w.cc\",\n \"sa909.com\",\n \"sad.qeo.cn\",\n \"safe.tsgpay.cn\",\n \"safe-aisle.jointreport-switch.com\",\n \"saferwet.com\",\n \"same.chinadaily.com.cn\",\n \"same.eastmoney.com\",\n \"same.jrj.com.cn\",\n \"same.mzy2014.com\",\n \"same.stockstar.com\",\n \"same01.jrj.com.cn\",\n \"same02.jrj.com.cn\",\n \"same03.jrj.com.cn\",\n \"sams.nikonimaging.com\",\n \"sangxi.top\",\n \"sanya1.com\",\n \"sape.ru\",\n \"sapi.sina.cn\",\n \"savebt.net\",\n \"saxxaz.taohuayuan8888.com\",\n \"sb.scorecardresearch.com\",\n \"sb88b.com\",\n \"sbeacon.sina.com.cn\",\n \"sbrqp.com\",\n \"sbw.ysjweb.com\",\n \"sc.58mingtian.cn\",\n \"sc.chinaiiss.com\",\n \"sc.ggdoubi.com\",\n \"sc.ggfeng.com\",\n \"sc.iasds01.com\",\n \"sc.sczxy.com\",\n \"sc.shayugg.com\",\n \"sc1369.com\",\n \"scc.0.0.0.0.cn\",\n \"sccdn.f2zd.com\",\n \"scdng.com\",\n \"scdown.qq.com\",\n \"scene.vip.xunlei.com\",\n \"schborg.com\",\n \"schemas.android.com\",\n \"schprompt.dangdang.com\",\n \"sciencelolb.com\",\n \"scimg.27admin.com\",\n \"sclick.6rooms.com\",\n \"sclick.baidu.com\",\n \"sclizhong.com\",\n \"sclog.moviebox.baofeng.com\",\n \"scorecardresearch.com\",\n \"scribe.twitter.com\",\n \"scrippsnetworks.com\",\n \"script.crazyegg.com\",\n \"script.vccoo.com\",\n \"script-bd.baixing.net\",\n \"scriptcc.cc\",\n \"scupio.com\",\n \"scw0.com\",\n \"sd.0.0.0.0.cn\",\n \"sd.kk3g.net\",\n \"sdac.lenovomm.com\",\n \"sdapprecv.app.cntvwb.cn\",\n \"sdb.amazonaws.com\",\n \"sdhzstone.net\",\n \"sdk.appadhoc.com\",\n \"sdk.cdnmaster.com\",\n \"sdk.cmgame.com\",\n \"sdk.conf.igexin.com\",\n \"sdk.mobad.ijinshan.com\",\n \"sdk.open.amp.igexin.com\",\n \"sdk.open.lbs.igexin.com\",\n \"sdk.open.phone.igexin.com\",\n \"sdk.open.talk.gepush.com\",\n \"sdk.open.talk.igexin.com\",\n \"sdkapp.mobile.sina.cn\",\n \"sdkapp.uve.weibo.com\",\n \"sdkclick.mobile.sina.cn\",\n \"sdkconfig.ad.intl.xiaomi.com\",\n \"sdkdm.com\",\n \"sdklog.cmgame.com\",\n \"sdklog.uu.cc\",\n \"sdkpay.uu.cc\",\n \"sdksitter.m.sjzhushou.com\",\n \"sdl.0.0.0.0.cn\",\n \"sdn.kugou.com\",\n \"sdn.penggua.com.cn\",\n \"sdownload.stargame.com\",\n \"sdqoi2d.com\",\n \"sdwfw.com\",\n \"sdycd.com\",\n \"sea.napi.ucweb.com\",\n \"searchignited.com\",\n \"searchswapper.com\",\n \"seavideo-ak.espn.go.com\",\n \"sebar.thand.info\",\n \"sec.resource.xiaomi.net\",\n \"secpay.wostore.cn\",\n \"secretmedia.s3.amazonaws.com\",\n \"secure.dsp.com\",\n \"secure.fastclick.net\",\n \"secure.img-cdn.mediaplex.com\",\n \"secure.quantserve.com\",\n \"secure.statcounter.com\",\n \"secure-asia.imrworldwide.com\",\n \"secure-assets.rubiconproject.com\",\n \"secure-chn.imrworldwide.com\",\n \"secure-ds.serving-sys.com\",\n \"security.browser.miui.com\",\n \"seen.h01ce.cn\",\n \"seen.hgo7r.cn\",\n \"seg.sharethis.com\",\n \"segment.com\",\n \"selfie.snapmobileasia.net\",\n \"sell1.etlong.com\",\n \"sensorsdata.ruguoapp.com\",\n \"serial.alcohol-soft.com\",\n \"serrano.hardwareheaven.com\",\n \"serve.popads.net\",\n \"servedby.keygamesnetwork.com\",\n \"server.m.pp.cn\",\n \"service.ad.adesk.com\",\n \"service.ad.duomi.com\",\n \"service.cocounion.com\",\n \"service.danmu.youku.com\",\n \"service.epro.sogou.com\",\n \"service.urchin.com\",\n \"servicer.adskeeper.co.uk\",\n \"serving-sys.com\",\n \"sestat.baidu.com\",\n \"setting.crashlytics.com\",\n \"setting.rayjump.com\",\n \"setting.snswin.qq.com\",\n \"settings.crashlytics.com\",\n \"sezvc.com\",\n \"sf3-fe-tos.pglstatp-toutiao.com\",\n \"sfloushi.com\",\n \"sg536.cn\",\n \"sgbfjs.info\",\n \"sg-cdn.effectivemeasure.net\",\n \"sgg.southcn.com\",\n \"sgvip.chinahdcm.com\",\n \"sh.qihoo.com\",\n \"sh.shuqw.com\",\n \"sha50.com\",\n \"shadu.baidu.com\",\n \"shaft.jebe.renren.com\",\n \"shama5.com\",\n \"shanghaironghua.com\",\n \"shanglinli.com\",\n \"shangz99991.com\",\n \"shankejingling.com\",\n \"share.gzdsw.com\",\n \"shared.youdao.com\",\n \"sharedaddomain.com\",\n \"sharrysweb.com\",\n \"shbywsd.cn\",\n \"shenghuo.xiaomi.com\",\n \"shenleyuni.com\",\n \"shenyian.net\",\n \"shenyun.com\",\n \"shenyun.org\",\n \"shenyunperformingarts.org\",\n \"shglegle.com\",\n \"shibeiou.com\",\n \"shiftrro.com\",\n \"shili.downxia.com\",\n \"shili.wanyx.com\",\n \"shiwan.dl.gxpan.cn\",\n \"shixunjs.th21333.com\",\n \"shke.kuuad.com\",\n \"shop.admin.yinyuetai.com\",\n \"shop.yinyuetai.com\",\n \"shop265.com\",\n \"shoppingpartners2.futurenet.com\",\n \"shouyoutan.com\",\n \"show.kc.taotaosou.com\",\n \"show.qx15.com\",\n \"show.xiazai16.com\",\n \"showcase.vpsboard.com\",\n \"showing.hardwareheaven.com\",\n \"shows.21cn.com\",\n \"shtt.shuqw.com\",\n \"shucaihangjia.com\",\n \"shuiguo.com\",\n \"shuqw.com\",\n \"shushijiameng123.com\",\n \"shuttle.bayescom.com\",\n \"shuzilm.cn\",\n \"shxinjie.cn\",\n \"shzyjbr.wtdtjs.rocks\",\n \"si9377.com\",\n \"sicentlife.com\",\n \"sifubo.cn\",\n \"sifuce.cn\",\n \"sifuda.cn\",\n \"sifufu.cn\",\n \"sifuge.cn\",\n \"sifugu.cn\",\n \"sifuhe.cn\",\n \"sifuhu.cn\",\n \"sifuji.cn\",\n \"sifuka.cn\",\n \"sigbusa.com\",\n \"sigo99.com\",\n \"simba.m.taobao.com\",\n \"sina.wrating.com\",\n \"sina.yinstar.org\",\n \"sinaalicdn.com\",\n \"sinaaliyun.cn\",\n \"siqwqjza.m.yikanxiaoshuo.net\",\n \"sis.jpush.io\",\n \"sit.gentags.net\",\n \"sit.pagechoice.net\",\n \"site.cdnmaster.com\",\n \"site.img.4tube.com\",\n \"sitemeter.com\",\n \"sitemobia.com\",\n \"sitescout.com\",\n \"sitetag.us\",\n \"sj.uukanshu.com\",\n \"sj1.3987.com\",\n \"sjj.jsyjwj.com\",\n \"skatehot.net\",\n \"sl.xawjwl.com\",\n \"slb.sxuantang.com\",\n \"slb.upshengyi.com\",\n \"slib.tvmao.cn\",\n \"slides.discovery.tom.com\",\n \"slog.sina.cn\",\n \"slog.sina.com.cn\",\n \"slot.union.ucweb.com\",\n \"slzs.52xiyou.com\",\n \"sm.0.0.0.0.cn\",\n \"sm1.todgo.com\",\n \"sm2.todgo.com\",\n \"smartmad.com\",\n \"smblock.s3.amazonaws.com\",\n \"smgru.net\",\n \"smucdn.com\",\n \"smxay.com\",\n \"smxsg.com\",\n \"snap.snapmobile.asia\",\n \"snapmobileasia.net\",\n \"sngmta.qq.com\",\n \"snnnyy.com\",\n \"snow001.com\",\n \"so9l.com\",\n \"soarfi.cn\",\n \"sobar.baidu.com\",\n \"sobartop.baidu.com\",\n \"social-touch.com\",\n \"sod.onelink.me\",\n \"soft.chaomeng8.com\",\n \"soft.zhidian3g.cn\",\n \"sohu.irs01.com\",\n \"sohu.wrating.com\",\n \"somecoding.com\",\n \"somennew.com\",\n \"song.fanxing.kugou.com\",\n \"song001.com\",\n \"sonomoyo.com\",\n \"sos0easy.com\",\n \"sou.dkdlsj.com\",\n \"sou.xanbhx.com\",\n \"souid.com\",\n \"source.youxiaoad.com\",\n \"sousuo.xm.sjzhushou.com\",\n \"sp.fastclick.net\",\n \"sp.gmossp-sp.jp\",\n \"sp.wndoor.com\",\n \"sp.yixui.com\",\n \"sp3.cndm.com\",\n \"spad.i-mobile.co.jp\",\n \"spade.twitch.tv\",\n \"spap.adingo.jp\",\n \"spap.adingo.jp.eimg.jp\",\n \"spapi.i-mobile.co.jp\",\n \"spb.bid.run\",\n \"spcdnpc.i-mobile.co.jp\",\n \"spcnv.i-mobile.co.jp\",\n \"spcode.baidu.com\",\n \"spdeliver.i-mobile.co.jp\",\n \"spdmg.i-mobile.co.jp\",\n \"spdmg-backend.i-mobile.co.jp\",\n \"sphwq.net\",\n \"spnet2-1.i-mobile.co.jp\",\n \"spnet33.i-mobile.co.jp\",\n \"sponsorpay.com\",\n \"sponsors.s2ki.com\",\n \"sponsors.webosroundup.com\",\n \"spproxy.autobytel.com\",\n \"spro.so.com\",\n \"spt.dictionary.com\",\n \"sqd.jstdjq.com\",\n \"sqext.com\",\n \"sqtpks3.1391.com\",\n \"squarespace.evyy.net\",\n \"src.duanxin520.com\",\n \"src.leju.com\",\n \"src.zf313.com\",\n \"srd.simba.taobao.com\",\n \"srhuafeng.com\",\n \"srv.carbonads.net\",\n \"srv.revdepo.com\",\n \"srv.thespacereporter.com\",\n \"ss.cnczjy.com\",\n \"ss.cnnic.cn\",\n \"ss.he9630.com\",\n \"ss.knet.cn\",\n \"ss.missyouxi.com\",\n \"ss.shicimingju.com\",\n \"ss.shuajuzu.com\",\n \"ss.subo.me\",\n \"ss.swagger1.com\",\n \"ss.sysad.cn\",\n \"ss.sysadult.cn\",\n \"ssac.suning.com\",\n \"sscefsol.com\",\n \"sscefsol.com.cn\",\n \"ssdaili.com\",\n \"ssh.hxlif.com\",\n \"ssh.jsyzw132.com\",\n \"ssh.lifu11.com\",\n \"ssh.szxiuchang.com\",\n \"ssh.yezijizhang.com\",\n \"ssjpx.com\",\n \"ssjy168.com\",\n \"ssl.google-analytics.com\",\n \"ssl.hyhzy.cn\",\n \"ssl.ymapp.com\",\n \"ssl-cdn.media.innity.net\",\n \"sso-cas.gridsumdissector.com\",\n \"ssp.08160.cn\",\n \"ssp.1rtb.com\",\n \"ssp.4hw.com.cn\",\n \"ssp.86str.com\",\n \"ssp.chaohutechan.com\",\n \"ssp.cibn.starschina.com\",\n \"ssp.daxueshengqiandai.com\",\n \"ssp.dmpdsp.com\",\n \"ssp.kjwx8.com\",\n \"ssp.kss.ksyun.com\",\n \"ssp.kssws.ks-cdn.com\",\n \"ssp.kxly360.com\",\n \"ssp.pro.cn\",\n \"ssp.tadseeker.com\",\n \"ssp.thescenseproject.com\",\n \"ssp.youxiaoad.com\",\n \"ssp.zf313.com\",\n \"ssp1.dmpdsp.com\",\n \"sspapi.youxiaoad.com\",\n \"ssp-bidder.i-mobile.co.jp\",\n \"ssp-rtb.sape.ru\",\n \"sss.jusha.com\",\n \"sss.sege.xxx\",\n \"sss.soarfi.cn\",\n \"sss.wzjmr.com\",\n \"sss.zbred.com\",\n \"sssvd.china.com\",\n \"sstc360.com\",\n \"ssum.casalemedia.com\",\n \"st.holalauncher.com\",\n \"st.holaworld.cn\",\n \"st.targetix.net\",\n \"st.yandexadexchange.net\",\n \"st.yengo.com\",\n \"sta.ganji.com\",\n \"sta.haloall.com\",\n \"sta.holagames.com\",\n \"sta.jcjk0451.com\",\n \"stadig.ifeng.com\",\n \"stadig0.ifeng.com\",\n \"staging.admin.e.mi.com\",\n \"staqnet.com\",\n \"star8.net\",\n \"startapp.com\",\n \"startappexchange.com\",\n \"startappservice.com\",\n \"startup.oupeng.com\",\n \"static1.kewaishu.info\",\n \"staticadm.leju.com\",\n \"staticadm.leju.sina.com.cn\",\n \"staticjs.cn\",\n \"statics.3987.com\",\n \"statics.9669.com\",\n \"statics.woozooo.com\",\n \"statictest.fraudmetrix.cn\",\n \"static-xl9-ssl.xunlei.com\",\n \"staticxx.facebook.com\",\n \"statisticsv2.yinyuetai.com\",\n \"stat-y.xywy.com\",\n \"stat-z.xywy.com\",\n \"steelhousemedia.com\",\n \"stervapoimenialena.info\",\n \"stg8.com\",\n \"stjzh.gdtarget.com\",\n \"st-n.ads3-adnow.com\",\n \"stn88.com\",\n \"stocksbsc.com\",\n \"storeconfig.mistat.xiaomi.com\",\n \"storewidget.pcauthority.com.au\",\n \"stream.heavenmedia.net\",\n \"stream.shuzilm.cn\",\n \"streaming.rtbiddingplatform.com\",\n \"strip.alicdn.com\",\n \"strip.taobaocdn.com\",\n \"su.8881919.cc\",\n \"su.bdimg.com\",\n \"su.bdstatic.com\",\n \"sub.powerapple.com\",\n \"sub.topber.com\",\n \"subswin.com\",\n \"sucodb.com\",\n \"sunjianhao.com\",\n \"suoooi.cn\",\n \"super.cat898.com\",\n \"super.kdnet.net\",\n \"supfast.net\",\n \"surv.xbizmedia.com\",\n \"susapi.dev.surepush.cn\",\n \"susapi.lenovomm.com\",\n \"suvset.sohu.com\",\n \"sv719.dreamdays.cn\",\n \"sw.cailawyer.cn\",\n \"sw.mobile.sogou.com\",\n \"swa.gtimg.com\",\n \"swappdl.duoyi.com\",\n \"switchadhub.com\",\n \"switching.atm.punchbox.org\",\n \"swpgjai.pop.weddingeeos.com\",\n \"swx.0.0.0.0.cn\",\n \"sxbhzs.net\",\n \"sxdyrq.com\",\n \"sxjxhg.com\",\n \"sxz67.com\",\n \"sy.code.mytanwan.com\",\n \"sy.flash.mytanwan.com\",\n \"sy.jlhygy.com\",\n \"sy.kcxsyz.com\",\n \"sy.shongcheng.com\",\n \"sy.sxjxhg.com\",\n \"sycbbs.com\",\n \"sy-cdnres.unionsy.com\",\n \"syilm.net\",\n \"sykty.com\",\n \"symaj.cn\",\n \"synacast.com\",\n \"sync.1dmp.io\",\n \"sync.1rx.io\",\n \"sync.adotmob.com\",\n \"sync.audsp.com\",\n \"sync.audtd.com\",\n \"sync.crwdcntrl.net\",\n \"sync.extend.tv\",\n \"sync.fastclick.net\",\n \"sync.intentiq.com\",\n \"sync.ipredictive.com\",\n \"sync.mathtag.com\",\n \"sync.morgdm.ru\",\n \"sync.rambler.ru\",\n \"sync.republer.com\",\n \"sync.teamrtb.net\",\n \"sync.tidaltv.com\",\n \"sync2.audtd.com\",\n \"sync-dsp.ad-m.asia\",\n \"sync-eu.exe.bid\",\n \"sync-tm.everesttech.net\",\n \"syndication.exdynsrv.com\",\n \"syndication.exoclick.com\",\n \"syndication.intel.com\",\n \"syndication.jsadapi.com\",\n \"syndication.twitter.com\",\n \"syndication1.viraladnetwork.net\",\n \"syndication-o.twitter.com\",\n \"syofew6o.net\",\n \"sys.zhangyue.com\",\n \"sysdig.com\",\n \"sytcyf.com\",\n \"sytsr.com\",\n \"sytz1288.com\",\n \"szb.aiyole.com\",\n \"szdzbx.com\",\n \"szfaq.com\",\n \"szggdw.com\",\n \"szkdst.com\",\n \"szrk3.com\",\n \"szshouzhai.com\",\n \"szxc868.com\",\n \"szxpsg.com\",\n \"szyr474.com\",\n \"t.2d-c.cn\",\n \"t.3apf.com\",\n \"t.adbxb.cn\",\n \"t.adcrops.net\",\n \"t.adxchina.cn\",\n \"t.atpanel.com\",\n \"t.cnsjx.net\",\n \"t.collect.yinyuetai.com\",\n \"t.cr-nielsen.com\",\n \"t.cyuew.com\",\n \"t.d.yoyi.tv\",\n \"t.dangdang.com\",\n \"t.dmtrck.com\",\n \"t.go.sohu.com\",\n \"t.growingio.com\",\n \"t.iz55.com\",\n \"t.oq68.com\",\n \"t.pingzei.com\",\n \"t.qiuqiuqipai.com\",\n \"t.sj.qq.com\",\n \"t.supermario.xyz\",\n \"t.trafmag.com\",\n \"t.tzcccm.com\",\n \"t.ujian.cc\",\n \"t.uvcourse.net\",\n \"t.youmi.net\",\n \"t1.58cdn.com.cn\",\n \"t1.jzkapp.com\",\n \"t1.visualrevenue.com\",\n \"t1.wshufa.com\",\n \"t188.dazhonghua.cn\",\n \"t2.58cdn.com.cn\",\n \"t2.jzkapp.com\",\n \"t2.vbxx.net\",\n \"t2.wshufa.com\",\n \"t3.58cdn.com.cn\",\n \"t70123.com\",\n \"t75.qyqc4s.com\",\n \"ta.qq.com\",\n \"ta80.com\",\n \"taat00889.com\",\n \"tactics.bainv.net\",\n \"tad.suning.com\",\n \"tag.cdnmaster.cn\",\n \"tag.digitaltarget.ru\",\n \"tags.growingio.com\",\n \"tags2.adshell.net\",\n \"tags4.revdepo.com\",\n \"tajs.qq.com\",\n \"tajxgs.com\",\n \"talk.nz.igexin.com\",\n \"tangoutianxia.com\",\n \"tansuotv.com\",\n \"tanwanyx.com\",\n \"tanx.com\",\n \"tanxlog.istreamsche.com\",\n \"tanzanite.infomine.com\",\n \"taobaly.cn\",\n \"taobaoaliyun.cn\",\n \"taobaobo5.com\",\n \"taobayun.cn\",\n \"taoggou.com\",\n \"taohanpai.com\",\n \"taomato.com\",\n \"tap.rubiconproject.com\",\n \"tap-cdn.rubiconproject.com\",\n \"tapjoy.cn\",\n \"tapjoy.com\",\n \"tapjoyads.com\",\n \"tap-t.rubiconproject.com\",\n \"targetedinfo.com\",\n \"targetedmedia.com.cn\",\n \"targetedtopic.com\",\n \"tatagou.com.cn\",\n \"tb.code.twyxi.com\",\n \"tb060x.corp.youdao.com\",\n \"tb104x.corp.youdao.com\",\n \"tbaocdn.com\",\n \"tbjfw.com\",\n \"tc.51la.net\",\n \"tc.ci123.com\",\n \"tc600.com\",\n \"tcad.wedolook.com\",\n \"tcjy66.cc\",\n \"tcss.qq.com\",\n \"tcxshop.com\",\n \"td.mpush.cn\",\n \"td.xue63.com\",\n \"tdayi.com\",\n \"t-e.flyme.cn\",\n \"teen.77rog.com\",\n \"telstra.imrworldwide.com\",\n \"temai.snssdk.com\",\n \"temai.taobao.com\",\n \"temp.163.com\",\n \"tencentmind.com\",\n \"tenddata.com\",\n \"test.api.xlmc.sandai.net\",\n \"test.eduancm.com\",\n \"test.surepush.cn\",\n \"textlink.simba.taobao.com\",\n \"tf.caohua.com\",\n \"tf.hdfdm.com\",\n \"tf.hftaili.com\",\n \"t-flow.flyme.cn\",\n \"tfssl.caohua.com\",\n \"tg.1155t.cn\",\n \"tg.52digua.com\",\n \"tg.jifen.2345.com\",\n \"tg.m.37.com\",\n \"tga.csbew.com\",\n \"tgb.csbew.com\",\n \"th21333.com\",\n \"th7.cn\",\n \"thejesperbay.com\",\n \"themis.yahoo.com\",\n \"thescenseproject.com\",\n \"thetestpage.39.net\",\n \"thoughtleadr.com\",\n \"thxnr.com\",\n \"thyvjboy.com\",\n \"thztv.net\",\n \"ti.tradetracker.net\",\n \"tiads.time.com\",\n \"tiangoutai.com\",\n \"tiangu99.com\",\n \"tianmidian.com\",\n \"tianqi777.com\",\n \"tianyanzs.com\",\n \"ticcdn.com\",\n \"timelog.moviebox.baofeng.com\",\n \"tiqcdn.com\",\n \"titan.babytree.com\",\n \"titan.guestworld.tripod.lycos.com\",\n \"titan01.babytree.com\",\n \"titi.qifajiang.cn\",\n \"tjf.lyhuayun.com\",\n \"tjhuajiantang.com\",\n \"tjlog.easou.com\",\n \"tjlog.ps.easou.com\",\n \"tjqonline.cn\",\n \"tjs.sjs.sinajs.cn\",\n \"tk.baidu.com\",\n \"tk.optaim.com\",\n \"tkd777.cn\",\n \"tkmdng.cn\",\n \"tkweb.baidu.com\",\n \"t-l.play.aiseet.atianqi.com\",\n \"tmcs.net\",\n \"tmisc.home.news.cn\",\n \"tns-counter.ru\",\n \"token.rubiconproject.com\",\n \"tongji-res1.meizu.com\",\n \"tongqing2015.com\",\n \"tool.btrabbit.la\",\n \"toolbar.baidu.com\",\n \"toolbar.msn.com\",\n \"toourbb.com\",\n \"top.h.qhimg.com\",\n \"top.h.qhmsg.com\",\n \"top267.com\",\n \"topitme.com\",\n \"total.xinmin.cn\",\n \"touclick.com\",\n \"toutiao.2haha.com\",\n \"toutiao.jxnews.com.cn\",\n \"tp.sgcn.com\",\n \"tpe163.com\",\n \"tpush.html5.qq.com\",\n \"tqd.ntpddq.com\",\n \"track-east.mobileadtrading.com\",\n \"trackersimulator.org\",\n \"tracking-server-prod-1.zenmxapps.com\",\n \"tradeadexchange.com\",\n \"tradeccl.com\",\n \"trafficfactory.biz\",\n \"trafficjam.cn\",\n \"trafficjunky.com\",\n \"trafficjunky.net\",\n \"trafficmp.com\",\n \"tralog.ganji.com\",\n \"tran.news.so.com\",\n \"tredman.com\",\n \"trends.mobile.sina.cn\",\n \"trial.alcohol-soft.com\",\n \"trwba.com\",\n \"trzina.com\",\n \"ts.hivecn.cn\",\n \"tsdlp.com\",\n \"tsjdgzm.m.3dllc.cc\",\n \"tsrc8.com\",\n \"tt.biquge.la\",\n \"tt.shxinjie.cn\",\n \"tt.twzui6.com\",\n \"tt123.eastday.com\",\n \"tt321.eastday.com\",\n \"ttcdn.cn\",\n \"ttlm.cc\",\n \"ttlowe.com\",\n \"ttm.htfmbt.com\",\n \"ttts.leztc.com\",\n \"ttts.miyue17.com\",\n \"tu.baixing.com\",\n \"tu.njflfd.com\",\n \"tu.szefe.com\",\n \"tuadong.com\",\n \"tuanxue360.net\",\n \"tui.gtimg.com\",\n \"tui1999.com\",\n \"tui98.cn\",\n \"tuia.cn\",\n \"tuidang.epochtimes.org\",\n \"tuidang.org\",\n \"tuigoo.com\",\n \"tuiguang.178.com\",\n \"tuiguang.meitu.com\",\n \"tuiguang.yicha.cn\",\n \"tuijian.baidu.com\",\n \"tuipenguin.com\",\n \"tuisong.baidu.com\",\n \"tuitiger.com\",\n \"tuituigui19999.com\",\n \"tujidao.com\",\n \"tukeai.com\",\n \"tukexiu.com\",\n \"tukj.net\",\n \"tumblrprobes.cedexis.com\",\n \"tumblrreports.cedexis.com\",\n \"tunion-api.m.taobao.com\",\n \"turn.com\",\n \"tv.code.jjyx.com\",\n \"tw.adon.vpon.com\",\n \"tw.adx.nextmedia.com\",\n \"tw.api.vpon.com\",\n \"tw.fgmtv.org\",\n \"tw.pub.vpon.com\",\n \"tw13b093.sandai.net\",\n \"twb98.com\",\n \"twcczhu.com\",\n \"twh5.com\",\n \"twinplan.com\",\n \"twitterzs.com\",\n \"twldmx.com\",\n \"twzui6.com\",\n \"tx.lwinl.com\",\n \"txt.go.sohu.com\",\n \"txtad.jijiplayer.com\",\n \"tylll.com\",\n \"tyu.quanliyouxi.cn\",\n \"tyx.xtzxmy.com\",\n \"tz.1688988.com\",\n \"tz.zjhoudao.com\",\n \"tzbtw.com\",\n \"tz-dsp.com\",\n \"u.63kc.com\",\n \"u.cnzol.com\",\n \"u.ddvip.com\",\n \"u.diannaodian.com\",\n \"u.huoying666.com\",\n \"u.jimdo.com\",\n \"u.qijipc.com\",\n \"u.raidmedia.com.cn\",\n \"u.uc123.com\",\n \"u.ucfly.com\",\n \"u.xcy8.com\",\n \"u.yiiwoo.com\",\n \"u.yizuya.com\",\n \"u0.s.minisplat.cn\",\n \"u034024.nr1234.com\",\n \"u1.img.mobile.sina.cn\",\n \"u1.s.minisplat.cn\",\n \"u1.shuaiku.com\",\n \"u2.s.minisplat.cn\",\n \"u291014.nr1234.com\",\n \"u349036.ff112222.com\",\n \"ua.badongo.com\",\n \"uapi.punchbox.org\",\n \"ubm.fangtoo.com\",\n \"uc.haoyunyuan.cc\",\n \"uc.xiansuper.com\",\n \"uc2.atobo.com.cn\",\n \"uc610.com\",\n \"uc9.ucweb.com\",\n \"ucaliyun.cn\",\n \"ucan.25pp.com\",\n \"ucqq.cnsptv.com.cn\",\n \"ucrzgcs.cn\",\n \"ucstat.baidu.com\",\n \"ucus.ucweb.com\",\n \"ucxxii.com\",\n \"uczzd.com\",\n \"uczzd.com.cn\",\n \"uczzd.net\",\n \"udata.mixmarket.biz\",\n \"udc.msn.com\",\n \"udm.scorecardresearch.com\",\n \"udrig.com\",\n \"udrwyjpwjfeg.com\",\n \"ue.ueadlian.com\",\n \"ue.yeyoucdn.com\",\n \"ueadlian.com\",\n \"uebawtz7.me\",\n \"ugc.moji001.com\",\n \"ugg.keefung-zs.com\",\n \"ugg66.com\",\n \"ugvip.com\",\n \"ui37.net\",\n \"uid.ksosoft.com\",\n \"uid.mdbchina.com\",\n \"uimg.27admin.com\",\n \"uimserv.net\",\n \"ujian.cc\",\n \"ujikdd041o.cn\",\n \"uk3oi.adgze.cn\",\n \"ukeiae.com\",\n \"ulic.baidu.com\",\n \"ulink.cc\",\n \"ultraiso.net\",\n \"um.simpli.fi\",\n \"um0592.com\",\n \"um2.eqads.com\",\n \"um29.com\",\n \"umid.orion.meizu.com\",\n \"umyai.com\",\n \"un.52rkl.cn\",\n \"un.soarfi.cn\",\n \"un.winasdaq.com\",\n \"un1.takefoto.cn\",\n \"unconf.mobad.ijinshan.com\",\n \"undm.qibulo.com\",\n \"unicast.ign.com\",\n \"unicast.msn.com\",\n \"unilog.wostore.cn\",\n \"unimhk.com\",\n \"union.baidu.com\",\n \"union.baidustatic.guannin.com\",\n \"union.china.com.cn\",\n \"union.dbba.cn\",\n \"union.maccms.com\",\n \"union.mop.com\",\n \"union.sogou.com\",\n \"union.star-media.cn\",\n \"union.youdao.com\",\n \"union1.xiaojianjian.net\",\n \"uniondm.cz88.net\",\n \"unionimage.baidu.com\",\n \"unionsy.com\",\n \"union-wifi.com\",\n \"unipaydl.wostore.cn\",\n \"unipayupg.wostore.cn\",\n \"unitacs.m.taobao.com\",\n \"unjs.jfcdns.com\",\n \"unlitui.com\",\n \"uns.soarfi.cn\",\n \"untitled.dwstatic.com\",\n \"uodoo.com\",\n \"uoyrsd.com\",\n \"up.cm.ksmobile.com\",\n \"up.hiao.com\",\n \"up4.ucweb.com\",\n \"upd.faronicslabs.com\",\n \"update.360safe.com\",\n \"update.avlyun.sec.miui.com\",\n \"update.bainv.net\",\n \"update.coolyun.com\",\n \"update.juw37xqo3x.com\",\n \"update.minipage.2345.com\",\n \"update.mobile.kugou.com\",\n \"update.sdk.jiguang.cn\",\n \"updatecenter.qq.com\",\n \"updatepage.kuwo.cn\",\n \"updates-s3.binaryage.com\",\n \"uplze.code.weddingeeos.com\",\n \"ups.ksmobile.net\",\n \"upush.res.meizu.com\",\n \"uqszvk.code.weddingeeos.com\",\n \"uqum.52shouyou.com.cn\",\n \"urbanairship.com\",\n \"urchin.5173.com\",\n \"urh.tylll.com\",\n \"urhu.cn\",\n \"uri6.com\",\n \"url.222bz.com\",\n \"url.tudown.com\",\n \"urls.api.twitter.com\",\n \"us.bannyat.com\",\n \"us.bs.serving-sys.com\",\n \"user.tiankongzudui.com\",\n \"usercollection.chinadaily.com.cn\",\n \"ushaqi.com\",\n \"usingde.com\",\n \"usr.mgid.com\",\n \"uss-pid.lenovomm.com\",\n \"usync.aws.rubiconproject.com\",\n \"ut2.shuqistat.com\",\n \"util.nphoto.net\",\n \"utility.baidu.com\",\n \"utility.rogersmedia.com\",\n \"utk.baidu.com\",\n \"utp.ucweb.com\",\n \"uu.feipukeplus.com\",\n \"uu.zeverdg.com\",\n \"uuidksinc.net\",\n \"uulucky.com\",\n \"uvclick.com\",\n \"uw9377.com\",\n \"uxip.meizu.com\",\n \"uyunad.com\",\n \"uzpmrbek.com\",\n \"v.dbncp.com\",\n \"v.e7002.com\",\n \"v.irs01.com\",\n \"v.oq68.com\",\n \"v.rmbn.net\",\n \"v.szpaopao.com\",\n \"v00087.com\",\n \"v02u9.cn\",\n \"v1.0594529.com\",\n \"v1.ujian.cc\",\n \"v12-r0566gbscjw.z.irs01.com\",\n \"v1-feed.idreamsky.com\",\n \"v2.fm.n.duokanbox.com\",\n \"v2.jiathis.com\",\n \"v3.jiathis.com\",\n \"v66v66.com\",\n \"v7.kawinhome.com\",\n \"v707070.com\",\n \"va.gxpan.cn\",\n \"vad1.jianshen8.com\",\n \"val.atm.cp31.ott.cibntv.net\",\n \"valf.atm.cp31.ott.cibntv.net\",\n \"vamaker.com\",\n \"vangmobi.com\",\n \"vas.funshion.com\",\n \"vatrack.hinet.net\",\n \"vcfs6ip5h6.bid\",\n \"vda.17173.com\",\n \"vdapprecv.app.cntvwb.cn\",\n \"vdazz.net\",\n \"ve.tsdlp.com\",\n \"vedeh.com\",\n \"vegaschina.cn\",\n \"vegent.cn\",\n \"vendor1.fitschigogerl.com\",\n \"ver.touclick.com\",\n \"verdict.abc.go.com\",\n \"vers80.com\",\n \"vg02h8z1ul.me\",\n \"vi0.mzy2014.com\",\n \"vi1.ku6img.net\",\n \"vi1.mzy2014.com\",\n \"vi1.souid.com\",\n \"vi2.ku6img.net\",\n \"vichc.com\",\n \"victorjx.com\",\n \"video.cooguo.com\",\n \"video.ureport.push.qq.com\",\n \"video.wap.mpush.qq.com\",\n \"videondun.com\",\n \"videopush.baidu.com\",\n \"viglink.com\",\n \"vimg.dwstatic.com\",\n \"vip.cainiaofx.com\",\n \"vip.hyz86.com\",\n \"vip.id528.com\",\n \"vip.jindu179.com\",\n \"vip.mall044.com\",\n \"vip.media8.cn\",\n \"vip.pinghuhome.com\",\n \"vip.qqxwf.com\",\n \"vip.zhuba8.com\",\n \"vipads.cn\",\n \"vista.tgbus.com\",\n \"vista.tgbusdata.cn\",\n \"visualscience.external.bbc.co.uk\",\n \"vj.x-ssp.com\",\n \"vj0.42422277.com\",\n \"vjcyehtqm9.me\",\n \"vl8c4g7tmo.me\",\n \"vlive.qqvideo.tc.qq.com\",\n \"vmzqwz.cn\",\n \"vn543.com\",\n \"vns800600.net\",\n \"vodlog.m1905.cn\",\n \"voiceads.cn\",\n \"voiceads.com\",\n \"voila.refr.adgtw.orangeads.fr\",\n \"vol.lflili.com\",\n \"vpon.com\",\n \"vps.inte.sogou.com\",\n \"vs.funshion.com\",\n \"vs19.gzcu.u3.ucweb.com\",\n \"vs2.gzcu.u3.ucweb.com\",\n \"vs7.gzcu.u3.ucweb.com\",\n \"vs8.gzct.u3.ucweb.com\",\n \"vs8.gzcu.u3.ucweb.com\",\n \"v-sence.gentags.net\",\n \"vsnoon.com\",\n \"vt.bjhdonline.com\",\n \"vtale.org\",\n \"vungle.cn\",\n \"vungle.com\",\n \"vupload.duowan.com\",\n \"vvlog.moviebox.baofeng.com\",\n \"vvv.ieduw.com\",\n \"vvvulqn7.com\",\n \"vwkhdi.cn\",\n \"vwws6.net\",\n \"vz-cdn.contentabc.com\",\n \"vz-cdn.trafficjunky.net\",\n \"w.bobocn.cn\",\n \"w.cube3d.cn\",\n \"w.gdown.baidu.com\",\n \"w.homes.yahoo.net\",\n \"w.jscsd.cn\",\n \"w.m.taobao.com\",\n \"w.punchbox.org\",\n \"w.sharethis.com\",\n \"w.waacorp.com\",\n \"w.werpig.com\",\n \"w.x.baidu.com\",\n \"w.xiaopiaoyou.com\",\n \"w.yamaidei.cn\",\n \"w.yinyuehu.cn\",\n \"w.ymapp.com\",\n \"w1.diaoyou.com\",\n \"w2528.com\",\n \"w3.yinyuehu.cn\",\n \"w3989.com\",\n \"w5sac788c1.360doc.cn\",\n \"w6061.move7.com\",\n \"w65p.com\",\n \"w8.com.cn\",\n \"w88.go.com\",\n \"wa.kuwo.cn\",\n \"wallet.advcash.com\",\n \"wan.2345.com\",\n \"wan.douyu.com\",\n \"wan.rising.cn\",\n \"wan.sogou.com\",\n \"wancai.com\",\n \"wanfeng1.com\",\n \"wangdaizao.com\",\n \"wangdq.com\",\n \"wangmeng.baidu.com\",\n \"wangmeng.sogou.com\",\n \"wangsufast.com\",\n \"wanproxy.127.net\",\n \"wantaico.com\",\n \"wantfour.com\",\n \"wap.114so.cn\",\n \"wap.138lm.com\",\n \"wap.bytdzsw.com\",\n \"wap.cmgame.com\",\n \"wap.moad.cn\",\n \"wap.mpush.qq.com\",\n \"wap.tanwan.com\",\n \"wap.txwdn.com\",\n \"wap.wooboo.com.cn\",\n \"wap001.bytravel.cn\",\n \"wap3.ucweb.com\",\n \"wapadv.com\",\n \"wappv.zol.com.cn\",\n \"waps.cn\",\n \"wapscdn.wapx.cn\",\n \"wapssl.ff113300.com\",\n \"wapwbclick.mobile.sina.cn\",\n \"wapx.cn\",\n \"wapx.com\",\n \"watson.live.com\",\n \"watson.microsoft.com\",\n \"wazero.online\",\n \"wb.gtimg.com\",\n \"wbapp.mobile.sina.cn\",\n \"wbclick.mobile.sina.cn\",\n \"wbpctips.mobile.sina.cn\",\n \"wbwl.houyi.baofeng.net\",\n \"wda.ydt.com.cn\",\n \"wd-edge.sharethis.com\",\n \"wdgsl.com\",\n \"wds.inte.sogoucdn.com\",\n \"wdzsb.com.cn\",\n \"we.tm\",\n \"weareqy.com\",\n \"web.900.la\",\n \"web.ali213.net\",\n \"web.data.pplive.com\",\n \"web.houyi.baofeng.net\",\n \"web.kuaisouwifi.com\",\n \"web.sogou.com\",\n \"webd.home.news.cn\",\n \"webdissector.com\",\n \"webkooo.com\",\n \"weblb-wg.gslb.spotify.com\",\n \"webmaster.extabit.com\",\n \"webmine.cz\",\n \"webstat.kuwo.cn\",\n \"webstat.ws.126.net\",\n \"webterren.com\",\n \"webtrends.yccdn.com\",\n \"weibomingzi.com\",\n \"weiguizhizuo.com\",\n \"weiqiqu.cn\",\n \"weishi.baidu.com\",\n \"weixiangzu.cn\",\n \"weixin.renrenying.com\",\n \"weixinvip.ren\",\n \"weld.iefsf.com\",\n \"weld.uunice.com\",\n \"weld830.uunice.com\",\n \"weldc1.021ye.com\",\n \"werpig.com\",\n \"weyyae.com\",\n \"wgie.0z5jn.cn\",\n \"wgnlz.com\",\n \"wgnmp.com\",\n \"whafwl.com\",\n \"whalecloud.com\",\n \"whcrdz.com\",\n \"whistleout.s3.amazonaws.com\",\n \"whn.star-media.cn\",\n \"whpxy.com\",\n \"whu.cwpush.com\",\n \"whytoss.com\",\n \"widget.criteo.com\",\n \"widget.crowdignite.com\",\n \"widget.directory.dailycommercial.com\",\n \"widget.kelkoo.com\",\n \"widget.raaze.com\",\n \"widget.searchschoolsnetwork.com\",\n \"widget.shopstyle.com.au\",\n \"widget.solarquotes.com.au\",\n \"widgets.comcontent.net\",\n \"widgets.realestate.com.au\",\n \"widnd.dajiadou6.com\",\n \"wifiapi01.51y5.net\",\n \"wifiapi02.51y5.net\",\n \"wifijia.net\",\n \"wifishow.ggsafe.com\",\n \"wikigifth.com\",\n \"winads.cn\",\n \"winasdaq.com\",\n \"winbaicai.com\",\n \"windcdna.com\",\n \"winlinebet.ru\",\n \"winvestern.com.cn\",\n \"wip3.adobe.com\",\n \"wisepush.video.baidu.com\",\n \"wiyun.com\",\n \"wjguc.com\",\n \"wka8.com\",\n \"wkanc.com\",\n \"wl.51taifu.com\",\n \"wl.eastlady.cn\",\n \"wl.houyi.baofeng.net\",\n \"wlkpa.cn\",\n \"wlneteller.adsrv.eacdn.com\",\n \"wlpinnaclesports.eacdn.com\",\n \"wm.20150.net\",\n \"wm.69shi.cn\",\n \"wm.baidu.com\",\n \"wm.lrswl.com\",\n \"wm.mipcdn.com\",\n \"wmcdn.qtmojo.cn\",\n \"wo.iuni.com.cn\",\n \"wo685.com\",\n \"woaizhongguo.cdn111222.com\",\n \"wodhid.com\",\n \"wole.us\",\n \"womenbaby.com\",\n \"womenwan.com\",\n \"wooboo.com.cn\",\n \"woocall.sina.com.cn\",\n \"woodpecker.uc.cn\",\n \"worldh5.gamehz.cn\",\n \"wowips.com\",\n \"wpc.32df9.rhocdn.net\",\n \"wpwdf.com\",\n \"wqmobile.com\",\n \"wqqsa.puzihua.com\",\n \"wqsph.net\",\n \"wrvdmh.cn\",\n \"ws.ksmobile.net\",\n \"ws.progrss.yahoo.com\",\n \"ws.sj.qq.com\",\n \"ws.tapjoyads.com\",\n \"ws.voiceads.cn\",\n \"ws1.datouniao.com\",\n \"ws2.cootekservice.com\",\n \"ws2.datouniao.com\",\n \"ws341.com\",\n \"ws7j.com\",\n \"wshufa.com\",\n \"wsoe.kwiago.com\",\n \"wsp.marketgid.com\",\n \"wstztt.com\",\n \"wtcpm.com\",\n \"wth.lenovomm.com\",\n \"wtpn.twenga.co.uk\",\n \"wtpn.twenga.de\",\n \"wtrace.cmgame.com\",\n \"wu65.com\",\n \"wudang05.com\",\n \"wuliao.epro.sogou.com\",\n \"wuliao.ganji.cn\",\n \"wuliao.juqingba.cn\",\n \"wumii.cn\",\n \"wumii.com\",\n \"wuqdebjfhjas.bid\",\n \"wuwho.cn\",\n \"ww.xiaopiaoyou.com\",\n \"ww10.onetad.com\",\n \"ww101.onetad.com\",\n \"ww11.onetad.com\",\n \"ww12.onetad.com\",\n \"ww13.onetad.com\",\n \"ww202.keyyou.net\",\n \"ww202.onetad.com\",\n \"ww34.onetad.com\",\n \"ww346.onetad.com\",\n \"ww360.onetad.com\",\n \"ww363.onetad.com\",\n \"ww366.onetad.com\",\n \"ww78.onetad.com\",\n \"ww8.onetad.com\",\n \"ww9.onetad.com\",\n \"wwis-dubc1-vip60.adobe.com\",\n \"wwv.onetad.com\",\n \"www2.xinmin.cn\",\n \"www-777563.com\",\n \"www8.xitek.com\",\n \"www9.effectivemeasure.net\",\n \"www9.enet.com.cn\",\n \"www91.intel.com\",\n \"wwwokzyzy.com\",\n \"wwww.495495.com\",\n \"wwww.551144.com\",\n \"wwww.640640.com\",\n \"wwww.649649.com\",\n \"wx.houyi.baofeng.net\",\n \"wx.paigu.com\",\n \"wx.xwjqr.com\",\n \"wx16999.com\",\n \"wxaw.tiantongmaoyi.com\",\n \"wxb.wxbdfm.com\",\n \"wxmmh.net\",\n \"wxsnsdy.tc.qq.com\",\n \"wxsnsdy.video.qq.com\",\n \"wxsnsdythumb.wxs.qq.com\",\n \"wxtz.houmags.com\",\n \"wxwm1.ikuailian.com\",\n \"wxwm2.ikuailian.com\",\n \"wy.ce22d.cn\",\n \"wyhzzy.com\",\n \"wysa.2wxb5.cn\",\n \"wyt.wwetjy.com\",\n \"wyttech.cn\",\n \"wzaigo.com\",\n \"wzj.ywrjgzs.com\",\n \"wzjijia.com\",\n \"x.120ask.com\",\n \"x.9dagui.com\",\n \"x.bidswitch.net\",\n \"x.bikaer.com\",\n \"x.castanet.net\",\n \"x.cnxad.com\",\n \"x.eroticity.net\",\n \"x.heyzap.com\",\n \"x.infzm.com\",\n \"x.ligatus.com\",\n \"x.vamaker.com\",\n \"x.vipergirls.to\",\n \"x.zhuyuanp.top\",\n \"x01.aidata.io\",\n \"x1.go.sohu.com\",\n \"x9377a.com\",\n \"xa9t.com\",\n \"xabaitai.com\",\n \"xabmjr.com\",\n \"xacqp.com\",\n \"xau.sxmutan.com\",\n \"xavingtsun.com\",\n \"xbp.code.weddingeeos.com\",\n \"xbtw.com\",\n \"xbzzzx.com\",\n \"xc.08an.com\",\n \"xc.macd.cn\",\n \"xc.mydrivers.com\",\n \"xcclzs.com\",\n \"xcdf.cn\",\n \"xchgx.com\",\n \"xcjy876.com\",\n \"xco.qwxcs.com\",\n \"xcy8.com\",\n \"xcyjzs.net\",\n \"xcyrc.com\",\n \"xd.code.tanwanyx.com\",\n \"xdadevelopers.browsi.mobi\",\n \"xdbwc.com\",\n \"xdcqcyp.com\",\n \"xdcs-collector.ximalaya.com\",\n \"xdyjt.com\",\n \"xe2c.com\",\n \"xf.yellowto.com\",\n \"xfo.monesyy.com\",\n \"xfywn.com\",\n \"xgcsr.com\",\n \"xgmc6lu8fs.me\",\n \"xhbqczl.com\",\n \"xhmrv.com\",\n \"xhsxgmt.cn\",\n \"xhsxgnt.cn\",\n \"xhtd.99hg.wang\",\n \"xhxnkyy.com\",\n \"xhydrs.cn\",\n \"xi.liuxiaoer.com\",\n \"xia.huishenghuiying.com\",\n \"xia.jihehuaban.com\",\n \"xiacai.com\",\n \"xiacaidd.com\",\n \"xianliao.me\",\n \"xiaobiaoucai.cn\",\n \"xiaohei.com\",\n \"xiaohuau.xyz\",\n \"xiaohui2.cn\",\n \"xiaomiir.yaokantv.com\",\n \"xiaoqiang\",\n \"xiaoshuo.kp53.cn\",\n \"xiaoshuo.zhandao.net\",\n \"xiaoyang.mobi\",\n \"xiaoyuanzuqiu.cn\",\n \"xiaoyutiao.com\",\n \"xiaozhen.com\",\n \"xiaozhishi852.com\",\n \"xiaxuanfu.com\",\n \"xiazai.cdren.com\",\n \"xiazai.downok.com\",\n \"xibao100.com\",\n \"xibei70.com\",\n \"xifatime.com\",\n \"xihashuale.com\",\n \"xihuashuale.com\",\n \"xilele.com\",\n \"xiliweisha.cn\",\n \"xin.ygqczh.com\",\n \"xinasiaj.com\",\n \"xinghao89.com\",\n \"xingjuhe.com\",\n \"xiniuz.com\",\n \"xinju.cc\",\n \"xinray.com\",\n \"xinsheng.net\",\n \"xiongdong.com\",\n \"xiuxiu.android.dl.meitu.com\",\n \"xiuxiu.mobile.meitudata.com\",\n \"xj40666.vip\",\n \"xji.qwxcs.com\",\n \"xjidian.com\",\n \"xjq.jxmqkj.com\",\n \"xk2012.com\",\n \"xkwfao.com\",\n \"xlmc.sandai.net\",\n \"xls.go.sohu.com\",\n \"xlwnx.com\",\n \"xlylqx.com\",\n \"xm9178.com\",\n \"xmcmn.com\",\n \"xmcxz.com\",\n \"xmindchina.net\",\n \"xmnmeu.cn\",\n \"xmrts.com\",\n \"xmshqh.com\",\n \"xmsqz.com\",\n \"xnjpg.com\",\n \"xoredi.com\",\n \"xp3366.com\",\n \"xpcy.m.gxwztv.com\",\n \"xpe.cxaerp.com\",\n \"xpj1.net\",\n \"xpj2.net\",\n \"xpj3.net\",\n \"xpj4.net\",\n \"xpj8088.com\",\n \"xpjkf888.com\",\n \"xpjylc9977.com\",\n \"xpqfc.com\",\n \"xq12.com\",\n \"xq199.com\",\n \"xrain.net\",\n \"xray.jebe.renren.com\",\n \"xs.1drj.com\",\n \"xs.he9630.com\",\n \"xs.houyi.baofeng.net\",\n \"xs.swagger1.com\",\n \"xshellcn.com\",\n \"xstar.cc\",\n \"xszqapp.com\",\n \"xtcdbb.cn\",\n \"xtgreat.com\",\n \"xtruh.uranus.sogou.com\",\n \"xtwjx.cn\",\n \"xtxa.net\",\n \"xtzxmy.com\",\n \"xuanmeiguoji.com\",\n \"xue.zbyw.cn\",\n \"xul478.com\",\n \"xulizui6.com\",\n \"xx.m.gxwztv.com\",\n \"xxad.cc\",\n \"xxeden.com\",\n \"xxguan.cn\",\n \"xxhrd.com\",\n \"xxkhh.com\",\n \"xxlargepop.com\",\n \"xxp.gytygc.com\",\n \"xxwkjl.com\",\n \"xxxa.aikeapp.com\",\n \"xxyzwtsylw.com\",\n \"xy.com\",\n \"xy.shijialianzuishuai.com\",\n \"xycnz.com\",\n \"xyd.sxmdxy.com\",\n \"xyimg.net\",\n \"xyly2016.com\",\n \"xyqptm.com\",\n \"xyqxr.com\",\n \"xyrhd.com\",\n \"xyrkl.com\",\n \"xyssp.com\",\n \"xytom.com\",\n \"xyxy01.com\",\n \"xyy.code.weddingeeos.com\",\n \"xz.ercfh.com\",\n \"xz-development.oss-cn-beijing.aliyuncs.com\",\n \"xzq.greenxf.net\",\n \"xztms.com\",\n \"xzyituo.com\",\n \"xzzyi.com\",\n \"y.3957957.com\",\n \"y.damifan.cn\",\n \"y.gwylm.com\",\n \"y.hk9600.com\",\n \"y.hzht666.com\",\n \"y.shuoshuocm.com\",\n \"y.xinghao89.com\",\n \"y.zxwdw.com\",\n \"y0.cn\",\n \"yadro.ru\",\n \"yads.c.yimg.jp\",\n \"yads.yahoo.co.jp\",\n \"yageben.com\",\n \"yam.adsbro.com\",\n \"yandui.com\",\n \"yangdasen.cn\",\n \"yanglaopt.net\",\n \"yao.zzsdjq.com\",\n \"yaohq.com\",\n \"yatemy.cn\",\n \"yb.torchbrowser.com\",\n \"ybtianxi.com\",\n \"yccdn.com\",\n \"ychml.com\",\n \"ychun03.com\",\n \"yd126.com\",\n \"ydjs.zol.com.cn\",\n \"ydlnt.com\",\n \"ydpushserver.youdao.com\",\n \"ydqzkj.com\",\n \"yea.uploadimagex.com\",\n \"yeabble.com\",\n \"yeas.yahoo.co.jp\",\n \"yee.js.cn\",\n \"yellowto.com\",\n \"yengo.com\",\n \"yesbeby.whies.info\",\n \"yess.imneinei.com\",\n \"yezilm.com\",\n \"yf898.com\",\n \"yfcode.m.gxwztv.com\",\n \"yfxpcode.m.gxwztv.com\",\n \"yfycy.com\",\n \"yhtcd.com\",\n \"yhzm.cc\",\n \"yicha.cn\",\n \"yidulive.net\",\n \"yieldmanager.com\",\n \"yigao.com\",\n \"yigyx.com\",\n \"yihuifu.cn\",\n \"yiiwoo.com\",\n \"yijia2009.com\",\n \"yijifen.com\",\n \"yiluup.com\",\n \"yin1.zgpingshu.com\",\n \"yingxiao.baidu.com\",\n \"yinhaijuan.com\",\n \"yinmong.com\",\n \"yinooo.com\",\n \"yinyuehu.cn\",\n \"yiqifa.com\",\n \"yiranxian.cn\",\n \"yitaopt.com\",\n \"yiwk.com\",\n \"yiwuds.com\",\n \"yixui.com\",\n \"yizhenya.com\",\n \"yjqiqi.com\",\n \"yk0712.com\",\n \"ykbei.com\",\n \"ykjmy.com\",\n \"yktj.yzz.cn\",\n \"ykxwn.com\",\n \"yl850555.com\",\n \"ylads.yaolan.com\",\n \"ylog.hiido.com\",\n \"ylunion.com\",\n \"ylwy168.com\",\n \"ymapp.com\",\n \"ymcdn.cn\",\n \"ymcqb.com\",\n \"ymrzr.com\",\n \"yn.001fzc.com\",\n \"ynbojie.com\",\n \"yndianju.com\",\n \"ynmbz.com\",\n \"yongkang6.com\",\n \"yongv.com\",\n \"yoo.yiiyoo.net\",\n \"yooli.com\",\n \"you1ad.com\",\n \"youfumei.com\",\n \"youjia2016.com\",\n \"youka.la\",\n \"youle.tom.com\",\n \"youle55.com\",\n \"youmi.net\",\n \"youmsm.com\",\n \"yousee.com\",\n \"youxi.kugou.com\",\n \"youxiaoad.com\",\n \"youxicool.net\",\n \"youzehui.com\",\n \"yoyi.com.cn\",\n \"yoyi.tv\",\n \"ypmeiwen.com\",\n \"ypmob.com\",\n \"yqjxzw.com\",\n \"yqw88.com\",\n \"yrt7dgkf.exashare.com\",\n \"yrxmr.com\",\n \"ysej.code.weddingeeos.com\",\n \"ysjwj.com\",\n \"ysm.hauchi.com.tw\",\n \"ysm.yahoo.com\",\n \"yt-adp.nosdn.127.net\",\n \"ytapi1.nagezan.net\",\n \"ytdksb.com\",\n \"ytguowang.com\",\n \"ytmx.2r3485.cn\",\n \"yts.ytsyyey.com\",\n \"ytsyyey.com\",\n \"yuanchengxiezuo.com\",\n \"yuanming.net\",\n \"yueyelive.com\",\n \"yug8.com\",\n \"yukhj.com\",\n \"yule8.net\",\n \"yulzs.com\",\n \"yumcs.xiaohuau.xyz\",\n \"yun.lvehaisen.com\",\n \"yun.rili.cn\",\n \"yun.sifuhe.cn\",\n \"yun.tuia.cn\",\n \"yun.tuisnake.com\",\n \"yun.yuyiya.com\",\n \"yun1.yahoo001.com\",\n \"yunanfuwuqi.com\",\n \"yunbofangbt.com\",\n \"yundingjiayuan.com\",\n \"yunjiasu.com\",\n \"yunshipei.com\",\n \"yunxuu.com\",\n \"yuyue008.cn\",\n \"ywjxsp168.cn\",\n \"yx.lenovomm.com\",\n \"yxhxs.com\",\n \"yxjad.com\",\n \"yxs.tymsyx.com\",\n \"yxszy.com\",\n \"yxxwyz.com\",\n \"yy58ju.com\",\n \"yyb.pc6.com\",\n \"yyffeicd.m.qxs.la\",\n \"yyjxgm.net\",\n \"yyp17.com\",\n \"yyt.irs01.com\",\n \"yzaosite.com\",\n \"yzh.jyjhkz.com\",\n \"yzh360.com\",\n \"yzygo.com\",\n \"yzytb.com\",\n \"z.clickvip.shop\",\n \"z.moatads.com\",\n \"z.nowscore.com\",\n \"z.sora.yoyi.com.cn\",\n \"z1.zedo.com\",\n \"z1hihu.xmcimg.com\",\n \"z2.lnymd.com\",\n \"zads.care2.com\",\n \"zae.gzzena.com\",\n \"zamar.cn\",\n \"zampdsp.com\",\n \"zantainet.com\",\n \"zapads.zapak.com\",\n \"zb.nxing.cn\",\n \"zbrushcn.com\",\n \"zbz.m.qxs.la\",\n \"zcdsp.com\",\n \"zcrtd.com\",\n \"zdjby.cn\",\n \"zdw.w8.com.cn\",\n \"ze5.com\",\n \"zedo.com\",\n \"zeus.qj.net\",\n \"zgc66.com\",\n \"zgdfz6h7po.me\",\n \"zgfszs.com\",\n \"zgjkv.com\",\n \"zgksb.com\",\n \"zgty365.com\",\n \"zgunion.cn\",\n \"zgyemy.com\",\n \"zhanzhang.net\",\n \"zhao258.com\",\n \"zhaoshang8.com\",\n \"zhaozecheng.cn\",\n \"zh-cn.shenyun.com\",\n \"zh-cn.shenyun.org\",\n \"zheng.cs12d.com\",\n \"zhengjian.org\",\n \"zhenxinet.com\",\n \"zhichi08.com\",\n \"zhidian3g.cn\",\n \"zhifenjie.com\",\n \"zhihei.com\",\n \"zhiong.net\",\n \"zhiyuanteam.com\",\n \"zhiziyun.com\",\n \"zhongchouyan.com\",\n \"zhongzicili.cc\",\n \"zhtjdl.com\",\n \"zhuanfakong.com\",\n \"zhuba8.com\",\n \"zhudiaosz.com\",\n \"zhuichaguoji.org\",\n \"zhushou.2345.com\",\n \"zhuuv.maoyumao.net\",\n \"zhwnlapi.etouch.cn\",\n \"zhybzp.cn\",\n \"zhzzx.com\",\n \"zisunion.com\",\n \"zizcy.com\",\n \"zjbdt.com\",\n \"zjhim.com\",\n \"zjjgtz.com\",\n \"zjm.zzmmkj.com\",\n \"zkrdy.com\",\n \"zlongad.com\",\n \"zlsw.nnjxqd.com\",\n \"zmj.guanqinjie.cn\",\n \"znsv.baidu.com\",\n \"zo66.com\",\n \"zp22938576.com\",\n \"zpe.klre.18183.com\",\n \"zq84.com\",\n \"zqworks.com\",\n \"zqzxz.com\",\n \"zreder.com\",\n \"zrpfk.com\",\n \"zs0613.mengchengbao.com\",\n \"zs1111.youzue.com\",\n \"zsdexun.com.cn\",\n \"zshacker.com\",\n \"zst.jzntxs.com\",\n \"zsxpx.com\",\n \"zszwcp.cn\",\n \"zt2088.com\",\n \"ztidu.com\",\n \"ztxbd.com\",\n \"zuche321.com\",\n \"zuiceshi.net\",\n \"zuimeitianqi.inveno.com\",\n \"zunmi.cn\",\n \"zws.avvo.com\",\n \"zx.baosmx.com\",\n \"zxcs.ggwan.com\",\n \"zxcs.linghit.com\",\n \"zxh.bzshzx.com\",\n \"zxjjzx.com\",\n \"zxr.fzxrjx.com\",\n \"zxziyuan.com\",\n \"zybpj.com\",\n \"zyf.fzdfwy.com\",\n \"zymo.mps.weibo.com\",\n \"zymro.com\",\n \"zytwq.net\",\n \"zyz.91friend.com\",\n \"zyz1.91friend.com\",\n \"zz.bdstatic.com\",\n \"zz123.com\",\n \"zzbaowen.com\",\n \"zzcw.office-mall.net\",\n \"zzd6.com\",\n \"zzjs2.firefang.cn\",\n \"zzpush.58.com\",\n \"zzrcz.com\",\n \"zzsx8.com\",\n \"zzy.mipujia.com\",\n \"zzy1.mipujia.com\",\n \"zzy1.quyaoya.com\",\n \"zzz7.52896368.com\",\n \"zzzzz4.52896368.com\",\n \"5534edee5a.com\",\n \"ea778a21c7.com\",\n \"baidustatic.com\",\n \"xdrig.com\",\n \"zhihu.xmcimg.com\"\n ],\n \"ip_cidr\": [\n \"101.227.97.240/32\",\n \"101.227.200.11/32\",\n \"101.227.200.28/32\",\n \"124.192.153.42/32\",\n \"117.177.248.17/32\",\n \"117.177.248.41/32\",\n \"223.87.176.139/32\",\n \"223.87.176.176/32\",\n \"223.87.177.180/32\",\n \"223.87.177.182/32\",\n \"223.87.177.184/32\",\n \"223.87.177.43/32\",\n \"223.87.177.47/32\",\n \"223.87.177.80/32\",\n \"223.87.182.101/32\",\n \"223.87.182.102/32\",\n \"223.87.182.11/32\",\n \"223.87.182.52/32\",\n \"39.107.15.115/32\",\n \"47.89.59.182/32\",\n \"103.49.209.27/32\",\n \"118.89.204.198/32\",\n \"123.56.152.96/32\",\n \"61.160.200.223/32\",\n \"61.160.200.242/32\",\n \"61.160.200.252/32\",\n \"61.174.50.214/32\",\n \"111.175.220.163/32\",\n \"111.175.220.164/32\",\n \"124.232.160.178/32\",\n \"175.6.223.15/32\",\n \"183.59.53.237/32\",\n \"218.93.127.37/32\",\n \"221.228.17.152/32\",\n \"221.231.6.79/32\",\n \"222.186.61.91/32\",\n \"222.186.61.95/32\",\n \"222.186.61.96/32\",\n \"222.186.61.97/32\",\n \"106.75.231.48/32\",\n \"119.4.249.166/32\",\n \"220.196.52.141/32\",\n \"221.6.4.148/32\",\n \"114.247.28.96/32\",\n \"221.179.131.72/32\",\n \"221.179.140.145/32\",\n \"10.72.25.0/24\",\n \"115.182.16.79/32\",\n \"118.144.88.126/32\",\n \"118.144.88.215/32\",\n \"120.76.189.132/32\",\n \"124.14.21.147/32\",\n \"124.14.21.151/32\",\n \"180.166.52.24/32\",\n \"220.115.251.25/32\",\n \"222.73.156.235/32\"\n ],\n \"domain\": [\n \"duclick.baidu.com\",\n \"hm.baidu.com\",\n \"hmma.baidu.com\",\n \"mobads.baidu.com\",\n \"mobads-logs.baidu.com\",\n \"nsclick.baidu.com\",\n \"wn.pos.baidu.com\",\n \"ps.map.baidu.com\",\n \"offnavi.map.baidu.com\",\n \"newvector.map.baidu.com\",\n \"ulog.imap.baidu.com\",\n \"newloc.map.n.shifen.com\",\n \"miniapp.bilibili.com\",\n \"thirdparty.biliapi.com\",\n \"log.star.ele.me\",\n \"ad.bn.netease.com\",\n \"ad.yixin.im\",\n \"iadmat.nosdn.127.net\",\n \"iadmusicmat.music.126.net\",\n \"iadmusicmatvideo.music.126.net\",\n \"impservice.dictapp.youdao.com\",\n \"impservice.youdao.com\",\n \"log.yex.youdao.com\",\n \"log-yex.youdao.com\",\n \"mr.da.netease.com\",\n \"n.3g.163.com\",\n \"nex.163.com\",\n \"pr.da.netease.com\",\n \"rd.da.netease.com\",\n \"wr.da.netease.com\",\n \"yt-adp.nosdn.127.net\",\n \"appcloud2.in.zhihu.com\",\n \"mqtt.zhihu.com\",\n \"sugar.zhihu.com\",\n \"zhihu-analytics.zhihu.com\",\n \"zhihu-web-analytics.zhihu.com\",\n \"118.89.204.198\"\n ],\n \"outbound\": \"AdBlock\"\n },\n {\n \"domain_suffix\": [\n \"fast.com\",\n \"netflix.ca\",\n \"netflix.com\",\n \"netflix.net\",\n \"netflixinvestor.com\",\n \"netflixtechblog.com\",\n \"nflxext.com\",\n \"nflximg.com\",\n \"nflximg.net\",\n \"nflxsearch.net\",\n \"nflxso.net\",\n \"nflxvideo.net\",\n \"netflix.com.edgesuite.net\"\n ],\n \"outbound\": \"Netflix\"\n },\n {\n \"domain_keyword\": [\n \"spotify\"\n ],\n \"domain_suffix\": [\n \"pscdn.co\",\n \"scdn.co\",\n \"spoti.fi\",\n \"spotilocal.com\"\n ],\n \"outbound\": \"Spotify\"\n },\n {\n \"domain_suffix\": [\n \"bamgrid.com\",\n \"cdn.registerdisney.go.com\",\n \"disney-plus.net\",\n \"disneyplus.com\",\n \"disneynow.com\",\n \"disneystreaming.com\",\n \"dssott.com\"\n ],\n \"outbound\": \"Disney\"\n },\n {\n \"domain_suffix\": [\n \"googlevideo.com\",\n \"gvt1.com\",\n \"video.google.com\",\n \"youtu.be\",\n \"youtube.ae\",\n \"youtube.al\",\n \"youtube.am\",\n \"youtube.at\",\n \"youtube.az\",\n \"youtube.ba\",\n \"youtube.be\",\n \"youtube.bg\",\n \"youtube.bh\",\n \"youtube.bo\",\n \"youtube.by\",\n \"youtube.ca\",\n \"youtube.cat\",\n \"youtube.ch\",\n \"youtube.cl\",\n \"youtube.co\",\n \"youtube.co.ae\",\n \"youtube.co.at\",\n \"youtube.co.cr\",\n \"youtube.co.hu\",\n \"youtube.co.id\",\n \"youtube.co.il\",\n \"youtube.co.in\",\n \"youtube.co.jp\",\n \"youtube.co.ke\",\n \"youtube.co.kr\",\n \"youtube.co.ma\",\n \"youtube.co.nz\",\n \"youtube.co.th\",\n \"youtube.co.tz\",\n \"youtube.co.ug\",\n \"youtube.co.uk\",\n \"youtube.co.ve\",\n \"youtube.co.za\",\n \"youtube.co.zw\",\n \"youtube.com\",\n \"youtube.com.ar\",\n \"youtube.com.au\",\n \"youtube.com.az\",\n \"youtube.com.bd\",\n \"youtube.com.bh\",\n \"youtube.com.bo\",\n \"youtube.com.br\",\n \"youtube.com.by\",\n \"youtube.com.co\",\n \"youtube.com.do\",\n \"youtube.com.ec\",\n \"youtube.com.ee\",\n \"youtube.com.eg\",\n \"youtube.com.es\",\n \"youtube.com.gh\",\n \"youtube.com.gr\",\n \"youtube.com.gt\",\n \"youtube.com.hk\",\n \"youtube.com.hn\",\n \"youtube.com.hr\",\n \"youtube.com.jm\",\n \"youtube.com.jo\",\n \"youtube.com.kw\",\n \"youtube.com.lb\",\n \"youtube.com.lv\",\n \"youtube.com.ly\",\n \"youtube.com.mk\",\n \"youtube.com.mt\",\n \"youtube.com.mx\",\n \"youtube.com.my\",\n \"youtube.com.ng\",\n \"youtube.com.ni\",\n \"youtube.com.om\",\n \"youtube.com.pa\",\n \"youtube.com.pe\",\n \"youtube.com.ph\",\n \"youtube.com.pk\",\n \"youtube.com.pt\",\n \"youtube.com.py\",\n \"youtube.com.qa\",\n \"youtube.com.ro\",\n \"youtube.com.sa\",\n \"youtube.com.sg\",\n \"youtube.com.sv\",\n \"youtube.com.tn\",\n \"youtube.com.tr\",\n \"youtube.com.tw\",\n \"youtube.com.ua\",\n \"youtube.com.uy\",\n \"youtube.com.ve\",\n \"youtube.cr\",\n \"youtube.cz\",\n \"youtube.de\",\n \"youtube.dk\",\n \"youtube.ee\",\n \"youtube.es\",\n \"youtube.fi\",\n \"youtube.fr\",\n \"youtube.ge\",\n \"youtube.googleapis.com\",\n \"youtube.gr\",\n \"youtube.gt\",\n \"youtube.hk\",\n \"youtube.hr\",\n \"youtube.hu\",\n \"youtube.ie\",\n \"youtube.in\",\n \"youtube.iq\",\n \"youtube.is\",\n \"youtube.it\",\n \"youtube.jo\",\n \"youtube.jp\",\n \"youtube.kr\",\n \"youtube.kz\",\n \"youtube.la\",\n \"youtube.lk\",\n \"youtube.lt\",\n \"youtube.lu\",\n \"youtube.lv\",\n \"youtube.ly\",\n \"youtube.ma\",\n \"youtube.md\",\n \"youtube.me\",\n \"youtube.mk\",\n \"youtube.mn\",\n \"youtube.mx\",\n \"youtube.my\",\n \"youtube.ng\",\n \"youtube.ni\",\n \"youtube.nl\",\n \"youtube.no\",\n \"youtube.pa\",\n \"youtube.pe\",\n \"youtube.ph\",\n \"youtube.pk\",\n \"youtube.pl\",\n \"youtube.pr\",\n \"youtube.pt\",\n \"youtube.qa\",\n \"youtube.ro\",\n \"youtube.rs\",\n \"youtube.ru\",\n \"youtube.sa\",\n \"youtube.se\",\n \"youtube.sg\",\n \"youtube.si\",\n \"youtube.sk\",\n \"youtube.sn\",\n \"youtube.soy\",\n \"youtube.sv\",\n \"youtube.tn\",\n \"youtube.tv\",\n \"youtube.ua\",\n \"youtube.ug\",\n \"youtube.uy\",\n \"youtube.vn\",\n \"youtubeeducation.com\",\n \"youtubeembeddedplayer.googleapis.com\",\n \"youtubei.googleapis.com\",\n \"youtubekids.com\",\n \"youtube-nocookie.com\",\n \"youtube-ui.l.google.com\",\n \"yt.be\",\n \"yt3.ggpht.com\",\n \"ytimg.com\"\n ],\n \"outbound\": \"YouTube\"\n },\n {\n \"domain_suffix\": [\n \"max.com\",\n \"discomax.com\",\n \"arkoselabs.com\",\n \"brightline.tv\",\n \"cdn.turner.com\",\n \"hbo.com\",\n \"hbomax.com\",\n \"ngtv.io\",\n \"pypestream.com\",\n \"warnermediacdn.com\",\n \"branch.io\"\n ],\n \"domain\": [\n \"app-analytics-services.com\",\n \"kpck4q-launches.appsflyersdk.com\",\n \"kpck4q-skadsdkless.appsflyersdk.com\",\n \"o0137140.ingest.us.sentry.io\",\n \"out053a3bejgh7t0phqa0csou.litix.io\",\n \"sdk.iad-01.braze.com\"\n ],\n \"outbound\": \"Max\"\n },\n {\n \"domain_suffix\": [\n \"acg.tv\",\n \"acgvideo.com\",\n \"b23.tv\",\n \"bilibili.com\",\n \"bilibili.tv\",\n \"biliapi.net\",\n \"biliapi.com\",\n \"bilivideo.com\",\n \"hdslb.com\"\n ],\n \"domain\": [\n \"upos-hz-mirrorakam.akamaized.net\",\n \"apiintl.biliapi.net\"\n ],\n \"outbound\": \"CN Mainland TV\"\n },\n {\n \"process_name\": [\n \"com.iqiyi.i18n\",\n \"com.iqiyi.i18n.tv\"\n ],\n \"domain_suffix\": [\n \"inter.iqiyi.com\",\n \"iq.com\",\n \"intl.iqiyi.com\"\n ],\n \"domain\": [\n \"intl-rcd.iqiyi.com\",\n \"intl-subscription.iqiyi.com\"\n ],\n \"ip_cidr\": [\n \"104.85.165.17/32\",\n \"110.238.107.47/32\",\n \"118.26.32.162/32\",\n \"159.138.102.146/32\",\n \"184.51.102.0/24\",\n \"203.74.95.130/28\",\n \"203.80.97.203/32\",\n \"210.71.227.202/32\",\n \"23.200.145.146/32\",\n \"23.210.215.186/32\",\n \"23.211.15.0/24\",\n \"23.219.172.0/24\",\n \"23.40.242.10/32\",\n \"23.59.252.0/24\"\n ],\n \"outbound\": \"CN Mainland TV\"\n },\n {\n \"domain_suffix\": [\n \"iqiyi.com\",\n \"iqiyipic.com\",\n \"iq.com\",\n \"qy.net\",\n \"gitv.tv\",\n \"71.am\"\n ],\n \"domain_keyword\": [\n \"qiyi\"\n ],\n \"domain\": [\n \"cache.video.iqiyi.com\"\n ],\n \"outbound\": \"CN Mainland TV\"\n },\n {\n \"domain_suffix\": [\n \"api.mob.app.letv.com\"\n ],\n \"outbound\": \"CN Mainland TV\"\n },\n {\n \"domain\": [\n \"apm.music.163.com\",\n \"apm3.music.163.com\",\n \"interface.music.163.com\",\n \"interface3.music.163.com\",\n \"music.163.com\"\n ],\n \"ip_cidr\": [\n \"101.71.154.241/32\",\n \"103.126.92.132/32\",\n \"103.126.92.133/32\",\n \"112.13.119.17/32\",\n \"112.13.122.1/32\",\n \"115.236.118.33/32\",\n \"115.236.121.1/32\",\n \"118.24.63.156/32\",\n \"193.112.159.225/32\",\n \"223.252.199.66/32\",\n \"223.252.199.67/32\",\n \"39.105.63.80/32\",\n \"45.254.48.1/32\",\n \"47.100.127.239/32\",\n \"59.111.160.195/32\",\n \"59.111.160.197/32\",\n \"59.111.181.35/32\",\n \"59.111.181.38/32\",\n \"59.111.181.60/32\"\n ],\n \"outbound\": \"CN Mainland TV\"\n },\n {\n \"domain_suffix\": [\n \"v.smtcdns.com\",\n \"vv.video.qq.com\"\n ],\n \"outbound\": \"CN Mainland TV\"\n },\n {\n \"domain_suffix\": [\n \"youku.com\"\n ],\n \"ip_cidr\": [\n \"106.11.0.0/16\"\n ],\n \"outbound\": \"CN Mainland TV\"\n },\n {\n \"domain_suffix\": [\n \"wetv.vip\",\n \"wetvinfo.com\"\n ],\n \"outbound\": \"CN Mainland TV\"\n },\n {\n \"domain_suffix\": [\n \"applemusic.com\",\n \"music.apple.com\",\n \"blobstore.apple.com\"\n ],\n \"domain\": [\n \"aod.itunes.apple.com\",\n \"aod-ssl.itunes.apple.com\",\n \"audio.itunes.apple.com\",\n \"audio-ssl.itunes.apple.com\",\n \"mvod.itunes.apple.com\",\n \"streamingaudio.itunes.apple.com\"\n ],\n \"outbound\": \"Apple TV\"\n },\n {\n \"domain\": [\n \"gspe1-ssl.ls.apple.com\"\n ],\n \"outbound\": \"Apple TV\"\n },\n {\n \"domain\": [\n \"np-edge.itunes.apple.com\",\n \"play-edge.itunes.apple.com\",\n \"uts-api.itunes.apple.com\"\n ],\n \"domain_suffix\": [\n \"tv.apple.com\"\n ],\n \"outbound\": \"Apple TV\"\n },\n {\n \"domain_suffix\": [\n \"abema-tv.com\",\n \"abema.io\",\n \"abema.tv\",\n \"ameba.jp\",\n \"hayabusa.io\"\n ],\n \"domain_keyword\": [\n \"abematv.akamaized.net\"\n ],\n \"outbound\": \"Asian TV\"\n },\n {\n \"domain_suffix\": [\n \"bahamut.com.tw\",\n \"gamer.com.tw\"\n ],\n \"domain\": [\n \"gamer-cds.cdn.hinet.net\",\n \"gamer2-cds.cdn.hinet.net\",\n \"bahamut.akamaized.net\"\n ],\n \"outbound\": \"Asian TV\"\n },\n {\n \"domain_suffix\": [\n \"akamaized.net\",\n \"foxplus.com\",\n \"theplatform.com\"\n ],\n \"outbound\": \"Asian TV\"\n },\n {\n \"domain_suffix\": [\n \"happyon.jp\",\n \"hulu.jp\",\n \"prod.hjholdings.tv\",\n \"streaks.jp\",\n \"yb.uncn.jp\"\n ],\n \"outbound\": \"Asian TV\"\n },\n {\n \"domain_keyword\": [\n \"japonx\",\n \"japronx\"\n ],\n \"domain_suffix\": [\n \"japonx.com\",\n \"japonx.tv\",\n \"japonx.net\",\n \"japonx.vip\",\n \"japronx.com\",\n \"japronx.tv\",\n \"japronx.net\",\n \"japronx.vip\"\n ],\n \"outbound\": \"Asian TV\"\n },\n {\n \"domain_suffix\": [\n \"joox.com\"\n ],\n \"outbound\": \"Asian TV\"\n },\n {\n \"domain_suffix\": [\n \"kkbox.com\",\n \"kkbox.com.tw\",\n \"kfs.io\"\n ],\n \"outbound\": \"Asian TV\"\n },\n {\n \"domain_suffix\": [\n \"kktv.me\",\n \"kktv.com.tw\"\n ],\n \"domain\": [\n \"kktv-theater.kk.stream\"\n ],\n \"outbound\": \"Asian TV\"\n },\n {\n \"domain_suffix\": [\n \"d3c7rimkq79yfu.cloudfront.net\",\n \"linetv.tw\",\n \"profile.line-scdn.net\"\n ],\n \"outbound\": \"Asian TV\"\n },\n {\n \"domain_keyword\": [\n \"nowtv100\",\n \"rthklive\"\n ],\n \"domain_suffix\": [\n \"mytvsuper.com\",\n \"tvb.com\"\n ],\n \"outbound\": \"Asian TV\"\n },\n {\n \"domain_suffix\": [\n \"dmc.nico\",\n \"nicovideo.jp\",\n \"nicodic.jp\",\n \"nicomanga.jp\",\n \"niconico.com\",\n \"nicoseiga.jp\",\n \"nimg.jp\",\n \"simg.jp\",\n \"socdm.com\"\n ],\n \"outbound\": \"Asian TV\"\n },\n {\n \"domain_suffix\": [\n \"bootstrapcdn.com\",\n \"cloudfront.net\",\n \"cognito-identity.us-east-1.amazonaws.com\",\n \"firebaseio.com\",\n \"jwpcdn.com\",\n \"jwplayer.com\",\n \"mobileanalytics.us-east-1.amazonaws.com\",\n \"nowe.com\",\n \"viu.com\",\n \"viu.tv\",\n \"viu.now.com\"\n ],\n \"outbound\": \"Asian TV\"\n },\n {\n \"domain_suffix\": [\n \"edgedatg.com\",\n \"go.com\"\n ],\n \"outbound\": \"Global TV\"\n },\n {\n \"domain_keyword\": [\n \"avoddashs\"\n ],\n \"domain_suffix\": [\n \"aiv-cdn.net\",\n \"aiv-delivery.net\",\n \"amazonprimevideo.cn\",\n \"amazonprimevideo.com.cn\",\n \"amazonprimevideos.com\",\n \"amazonvideo.cc\",\n \"amazonvideo.com\",\n \"amazonvideodirect.cc\",\n \"atv-ext-eu.amazon.com\",\n \"atv-ext-fe.amazon.com\",\n \"atv-ext.amazon.com\",\n \"atv-ps-eu.amazon.co.uk\",\n \"atv-ps-eu.amazon.com\",\n \"atv-ps-fe.amazon.co.jp\",\n \"atv-ps-fe.amazon.com\",\n \"atv-ps.amazon.com\",\n \"fls-na.amazon.com\",\n \"media-amazon.com\",\n \"prime-video.com\",\n \"primevideo.cc\",\n \"primevideo.com\",\n \"primevideo.info\",\n \"primevideo.org\",\n \"primevideo.tv\",\n \"pv-cdn.net\",\n \"video.a2z.com\"\n ],\n \"domain\": [\n \"avodmp4s3ww-a.akamaihd.net\",\n \"d1v5ir2lpwr8os.cloudfront.net\",\n \"d1y002tclu9djj.cloudfront.net\",\n \"d22qjgkvxw22r6.cloudfront.net\",\n \"d25xi40x97liuc.cloudfront.net\",\n \"dmqdd6hw24ucf.cloudfront.net\",\n \"d27xxe7juh1us6.cloudfront.net\",\n \"dualstack.pefs-alb-266603904.eu-west-1.elb.amazonaws.com\"\n ],\n \"outbound\": \"Global TV\"\n },\n {\n \"domain_keyword\": [\n \"-uk-live.akamaized.net\",\n \"bbcfmt\"\n ],\n \"domain_suffix\": [\n \"bbc.co\",\n \"bbc.co.uk\",\n \"bbc.com\",\n \"bbcfmt.hs.llnwd.net\",\n \"bbci.co\",\n \"bbci.co.uk\",\n \"bidi.net.uk\"\n ],\n \"outbound\": \"Global TV\"\n },\n {\n \"process_name\": [\n \"com.dazn\"\n ],\n \"domain_suffix\": [\n \"dazn-api.com\",\n \"dazn.com\",\n \"dazndn.com\",\n \"indazn.com\",\n \"indaznlab.com\",\n \"dcalivedazn.akamaized.net\",\n \"dcblivedazn.akamaized.net\",\n \"dc1live2lindazn.akamaized.net\",\n \"dc1-lm-live2dazn.secure.footprint.net\",\n \"dc1voddazn.akamaized.net\",\n \"dc2voddazn.akamaized.net\"\n ],\n \"outbound\": \"Global TV\"\n },\n {\n \"domain_suffix\": [\n \"content-ause1-ur-discovery1.uplynk.com\",\n \"disco-api.com\",\n \"discoveryplus.com\",\n \"fwmrm.net\",\n \"getblueshift.com\",\n \"litix.io\",\n \"mobile-collector.newrelic.com\",\n \"uplynk.com\"\n ],\n \"outbound\": \"Global TV\"\n },\n {\n \"domain_suffix\": [\n \"encoretvb.com\"\n ],\n \"domain\": [\n \"content.jwplatform.com\",\n \"videos-f.jwpsrv.com\"\n ],\n \"outbound\": \"Global TV\"\n },\n {\n \"domain\": [\n \"d2n9h2wits23hf.cloudfront.net\",\n \"f1prodlive.akamaized.net\",\n \"mobile-collector.newrelic.com\"\n ],\n \"domain_suffix\": [\n \"bitmovin.com\",\n \"f1esports.com\",\n \"f1manager.com\",\n \"f1play.com\",\n \"formula1.com\"\n ],\n \"outbound\": \"Global TV\"\n },\n {\n \"domain_suffix\": [\n \"fox.com\",\n \"foxdcg.com\",\n \"uplynk.com\"\n ],\n \"outbound\": \"Global TV\"\n },\n {\n \"ip_cidr\": [\n \"8.28.124.0/23\",\n \"199.60.116.0/24\",\n \"199.200.48.0/22\",\n \"208.91.156.0/22\"\n ],\n \"domain_suffix\": [\n \"hulu.com\",\n \"hulu.hb.omtrdc.net\",\n \"hulu.sc.omtrdc.net\",\n \"huluad.com\",\n \"huluim.com\",\n \"hulumail.com\",\n \"huluqa.com\",\n \"hulustream.com\"\n ],\n \"domain\": [\n \"cs428.wpc.edgecastcdn.net\",\n \"cws-hulu.conviva.com\",\n \"hulu.com.c.footprint.net\",\n \"hulu.map.fastly.net\"\n ],\n \"outbound\": \"Global TV\"\n },\n {\n \"domain_suffix\": [\n \"pandora.com\"\n ],\n \"outbound\": \"Global TV\"\n },\n {\n \"domain_suffix\": [\n \"pbs.org\"\n ],\n \"outbound\": \"Global TV\"\n },\n {\n \"domain_suffix\": [\n \"phncdn.com\",\n \"phprcdn.com\",\n \"pornhub.com\",\n \"pornhubpremium.com\"\n ],\n \"outbound\": \"Global TV\"\n },\n {\n \"domain_suffix\": [\n \"sndcdn.com\",\n \"soundcloud.app.goo.gl\",\n \"soundcloud.com\",\n \"soundcloudmail.com\"\n ],\n \"outbound\": \"Global TV\"\n },\n {\n \"domain_suffix\": [\n \"t.me\",\n \"tx.me\",\n \"tdesktop.com\",\n \"telegra.ph\",\n \"telegram.me\",\n \"telegram.org\",\n \"telegram-cdn.org\",\n \"cdn-telegram.org\",\n \"telesco.pe\"\n ],\n \"domain_keyword\": [\n \"telegram\"\n ],\n \"ip_cidr\": [\n \"91.105.192.0/23\",\n \"91.108.56.0/22\",\n \"91.108.4.0/22\",\n \"91.108.8.0/22\",\n \"91.108.12.0/22\",\n \"91.108.16.0/22\",\n \"91.108.20.0/22\",\n \"95.161.64.0/20\",\n \"149.154.160.0/20\",\n \"185.76.151.0/24\"\n ],\n \"outbound\": \"Telegram\"\n },\n {\n \"domain_suffix\": [\n \"s.team\",\n \"steampowered.com\",\n \"steamcommunity.com\",\n \"steamgames.com\",\n \"steamusercontent.com\",\n \"steamstatic.com\"\n ],\n \"outbound\": \"Steam\"\n },\n {\n \"domain_suffix\": [\n \"fast.com\",\n \"ooklaserver.net\",\n \"speed.cloudflare.com\"\n ],\n \"domain_keyword\": [\n \"speedtest\"\n ],\n \"domain\": [\n \"speed.dler.io\"\n ],\n \"outbound\": \"Speedtest\"\n },\n {\n \"domain_keyword\": [\n \"paypal\"\n ],\n \"domain_suffix\": [\n \"paypal.com\",\n \"paypalobjects.com\"\n ],\n \"outbound\": \"PayPal\"\n },\n {\n \"domain_suffix\": [\n \"here.com\",\n \"here.net\",\n \"heremaps.cn\",\n \"ovi.com.cn\",\n \"azure\",\n \"azure-apim.net\",\n \"azure-dns.com\",\n \"azure-dns.info\",\n \"azure-dns.net\",\n \"azure-dns.org\",\n \"azure-mobile.net\",\n \"azure-sphere.com\",\n \"azure-test.net\",\n \"azure.cn\",\n \"azure.com\",\n \"azure.net\",\n \"azurecomcdn.net\",\n \"azurecontainer.io\",\n \"azurecosmos.net\",\n \"azurecosmosdb.com\",\n \"azurecosmosdb.info\",\n \"azurecosmosdb.net\",\n \"azuredatabricks.net\",\n \"azuredevopslaunch.com\",\n \"azuredigitaltwin.com\",\n \"azuredigitaltwins.com\",\n \"azuredigitaltwins.net\",\n \"azuredns-prd.info\",\n \"azuredns-prd.org\",\n \"azureedge-test.net\",\n \"azureedge.net\",\n \"azurefd.net\",\n \"azurefd.us\",\n \"azureiotcentral.com\",\n \"azureiotsolutions.com\",\n \"azureiotsuite.com\",\n \"azureplanetscale.info\",\n \"azureplanetscale.net\",\n \"azureserviceprofiler.com\",\n \"azuresmartspaces.net\",\n \"azurestackvalidation.com\",\n \"azurewebsites.net\",\n \"chinacloudapi.cn\",\n \"chinacloudapp.cn\",\n \"chinacloudsites.cn\",\n \"cosmosdb.info\",\n \"cosmosdb.net\",\n \"devopsms.com\",\n \"gotcosmos.com\",\n \"microsofteca.com\",\n \"microsoftiotcentral.com\",\n \"serverlesslibrary.net\",\n \"signalr.net\",\n \"tryfunctions.com\",\n \"windowsazure.cn\",\n \"windowsazure.com\",\n \"azure.microsoft.com\",\n \"azuremarketplace.microsoft.com\",\n \"bbing.com\",\n \"bibg.com\",\n \"biing.com\",\n \"binb.com\",\n \"binf.com\",\n \"bing\",\n \"bing.com\",\n \"bing.com.cn\",\n \"bing.net\",\n \"bing123.com\",\n \"bing135.com\",\n \"bing4.com\",\n \"bingads.com\",\n \"bingagencyawards.com\",\n \"bingapis.com\",\n \"bingapistatistics.com\",\n \"binginternal.com\",\n \"bingit.net\",\n \"bingiton.com\",\n \"bingj.com\",\n \"bingpix.com\",\n \"bingpk.com\",\n \"bings.com\",\n \"bingsandbox.com\",\n \"bingtoolbar.com\",\n \"bingtranslator.com\",\n \"bingvisualsearch.com\",\n \"bingworld.com\",\n \"biying.cn\",\n \"biying.com\",\n \"biying.com.cn\",\n \"bluehatnights.com\",\n \"dictate.ms\",\n \"discoverbing.com\",\n \"explorebing.com\",\n \"flipwithsurface.com\",\n \"mapblast.com\",\n \"mappoint.com\",\n \"masalladeloslimites.com\",\n \"microsoft-give.com\",\n \"microsoftcloudsummit.com\",\n \"microsoftdiplomados.com\",\n \"microsoftlatamholiday.com\",\n \"microsoftmxfilantropia.com\",\n \"microsoftpartnersolutions.com\",\n \"msnmaps.com\",\n \"msunlimitedcloudsummit.com\",\n \"myhomemsn.com\",\n \"office365love.com\",\n \"office365tw.com\",\n \"osdinfra.net\",\n \"renovacionoffice.com\",\n \"sprinklesapp.com\",\n \"working-bing-int.com\",\n \"bj1.api.bing.com\",\n \"emoi-cncdn.bing.com\",\n \"cn.bing.com\",\n \"cn.bing.net\",\n \"ditu.live.com\",\n \"a-msedge.net\",\n \"c-msedge.net\",\n \"e-msedge.net\",\n \"edgesuite.net\",\n \"evoke-windowsservices-tas.msedge\",\n \"microsoftedge.com\",\n \"microsoftedgeinsider.com\",\n \"msedge.net\",\n \"s-msedge.net\",\n \"femalefounderscomp.com\",\n \"m12.vc\",\n \"adaptivecards.io\",\n \"api-extractor.com\",\n \"apisof.net\",\n \"appcenter.ms\",\n \"blazor.net\",\n \"botframework.com\",\n \"codethemicrobit.com\",\n \"devopsassessment.net\",\n \"dot.net\",\n \"exp-tas.com\",\n \"gamesstack.com\",\n \"graphengine.io\",\n \"insiderdevtour.com\",\n \"jwt.ms\",\n \"microbit.org\",\n \"microsoftadc.com\",\n \"microsoftgamestack.com\",\n \"microsoftiotinsiderlabs.com\",\n \"microsoftreactor.cn\",\n \"microsoftreactor.com.cn\",\n \"microsoftreactor.info\",\n \"microsoftreactor.net\",\n \"microsoftreactor.org\",\n \"microsoftsilverlight.com\",\n \"microsoftsilverlight.net\",\n \"microsoftsilverlight.org\",\n \"microsoftsqlserver.com\",\n \"mmdnn.com\",\n \"mono-project.com\",\n \"msdn.com\",\n \"msinnovationchallenge.com\",\n \"mspairlift.com\",\n \"msropendata.com\",\n \"nuget.org\",\n \"nugettest.org\",\n \"opentranslatorstothings.org\",\n \"poshtestgallery.com\",\n \"pwabuilder.com\",\n \"reactorms.com.cn\",\n \"sankie.net\",\n \"sqlserveronlinux.com\",\n \"timelinestoryteller.com\",\n \"uwpcommunitytoolkit.com\",\n \"vfsforgit.com\",\n \"vfsforgit.org\",\n \"xamarin.com\",\n \"developer.microsoft.com\",\n \"dtlgalleryint.cloudapp.net\",\n \"poshtestgallery.cloudapp.net\",\n \"psg-int-centralus.cloudapp.net\",\n \"psg-int-eastus.cloudapp.net\",\n \"microsoft-online.cn\",\n \"microsoft-online.com.cn\",\n \"microsoftnews.cc\",\n \"microsoftnews.cn\",\n \"microsoftnews.com\",\n \"microsoftnews.net\",\n \"microsoftnews.org\",\n \"microsoftnewsforkids.com\",\n \"microsoftnewsforkids.net\",\n \"microsoftnewsforkids.org\",\n \"microsoftnewskids.com\",\n \"microsoftnewskids.net\",\n \"microsoftnewskids.org\",\n \"microsoftol.com\",\n \"microsoftol.com.cn\",\n \"microsoftusercontent.com\",\n \"msn.cn\",\n \"msn.com\",\n \"msn.com.cn\",\n \"msn.com.nsatc.net\",\n \"msn.com.tw\",\n \"msnewskids.com\",\n \"msnewskids.net\",\n \"msnewskids.org\",\n \"msnkids.com\",\n \"winmp.cn\",\n \"o365cn.com\",\n \"o365files.cn\",\n \"o365weve-dev.com\",\n \"o365weve-ppe.com\",\n \"o365weve.com\",\n \"office\",\n \"office.com\",\n \"office.net\",\n \"office365.com\",\n \"officedev.cn\",\n \"1drv.com\",\n \"1drv.ms\",\n \"livefilestore.com\",\n \"onedrive.co\",\n \"onedrive.co.uk\",\n \"onedrive.com\",\n \"onedrive.eu\",\n \"onedrive.live.com\",\n \"onedrive.net\",\n \"onedrive.org\",\n \"storage.live.com\",\n \"groupme.com\",\n \"skype.com\",\n \"skype.net\",\n \"skypeassets.com\",\n \"skypeassets.net\",\n \"skypeforbusiness.com\",\n \"sway-cdn.com\",\n \"sway-extensions.com\",\n \"sway.com\",\n \"visualstudio-staging.com\",\n \"visualstudio.co\",\n \"visualstudio.co.uk\",\n \"visualstudio.com\",\n \"visualstudio.eu\",\n \"visualstudio.net\",\n \"vsassets.io\",\n \"vscode-unpkg.net\",\n \"vscode-webview.net\",\n \"vscode.dev\",\n \"live.cn\",\n \"live.com.akadns.net\",\n \"sclive.net\",\n \"windowslive.cn\",\n \"wlxrs.com\",\n \"aicscience.com\",\n \"mmais.com.cn\",\n \"msminico.cn\",\n \"msminico.com.cn\",\n \"msxiaobing.com\",\n \"msxiaoice.com\",\n \"msxiaona.cn\",\n \"officeplus.cn\",\n \"renlifang.com\",\n \"cortana.ai\",\n \"cortanaanalytics.com\",\n \"cortanaskills.com\",\n \"forzamotorsport.net\",\n \"forzaracingchampionship.com\",\n \"forzarc.com\",\n \"gamepass.com\",\n \"msgamestudios.com\",\n \"orithegame.com\",\n \"renovacionxboxlive.com\",\n \"tellmewhygame.com\",\n \"xbox.co\",\n \"xbox.com\",\n \"xbox.eu\",\n \"xbox.org\",\n \"xbox360.co\",\n \"xbox360.com\",\n \"xbox360.eu\",\n \"xbox360.org\",\n \"xboxab.com\",\n \"xboxgamepass.com\",\n \"xboxgamestudios.com\",\n \"xboxlive.cn\",\n \"xboxlive.com\",\n \"xboxone.co\",\n \"xboxone.com\",\n \"xboxone.eu\",\n \"xboxplayanywhere.com\",\n \"xboxservices.com\",\n \"xboxstudios.com\",\n \"xbx.lv\",\n \"callersbane.com\",\n \"minecraft.net\",\n \"minecraftshop.com\",\n \"mojang.com\",\n \"beth.games\",\n \"bethesda.net\",\n \"bethesdagamestudios.com\",\n \"bethsoft.com\",\n \"applicationinsights.io\",\n \"applicationinsights.net\",\n \"aadrm.com\",\n \"acompli.net\",\n \"aka.ms\",\n \"ankarazirvesi2018.com\",\n \"applicationinsights.io\",\n \"applicationinsights.net\",\n \"aria.ms\",\n \"asp.net\",\n \"aspnetcdn.com\",\n \"assets-yammer.com\",\n \"azurerms.com\",\n \"binads.com\",\n \"bluehatil.com\",\n \"boswp.com\",\n \"brazilpartneruniversity.com\",\n \"breakdown.me\",\n \"centralvalidation.com\",\n \"ch9.ms\",\n \"charticulator.com\",\n \"cloudapp.net\",\n \"cloudappsecurity.com\",\n \"crmdynint-gcc.com\",\n \"crmdynint.com\",\n \"crossborderexpansion.com\",\n \"docs.com\",\n \"dwh5.com\",\n \"dynamics.com\",\n \"efproject.net\",\n \"engkoo.com\",\n \"fasttrackreadysupport.com\",\n \"fluidpreview.com\",\n \"footprintdns.com\",\n \"gameuxmasterguide.com\",\n \"gears5.com\",\n \"gearspop.com\",\n \"gearstactics.com\",\n \"getmicrosoftkey.com\",\n \"gfx.ms\",\n \"gigjam.com\",\n \"helpshift.com\",\n \"hockeyapp.net\",\n \"hololens.com\",\n \"hotmail\",\n \"hotmail.co\",\n \"hotmail.com\",\n \"hotmail.eu\",\n \"hotmail.net\",\n \"hotmail.org\",\n \"hummingbird.ms\",\n \"ie10.com\",\n \"ie11.com\",\n \"ie8.co\",\n \"ie9.com\",\n \"imaginecup.pl\",\n \"img-prod-cms-rt-microsoft-com\",\n \"ingads.com\",\n \"internetexplorer.co\",\n \"internetexplorer.com\",\n \"intunewiki.com\",\n \"iotinactionevents.com\",\n \"joinms.com\",\n \"joinms.com.cn\",\n \"joinmva.com\",\n \"kidgrid.tv\",\n \"kumo.com\",\n \"latampartneruniversity.com\",\n \"live.com\",\n \"live.com.au\",\n \"live.eu\",\n \"live.net\",\n \"livingyourambition.com\",\n \"localytics.com\",\n \"lync.com\",\n \"makecode.org\",\n \"managedmeetingrooms.com\",\n \"meetfasttrack.com\",\n \"meetyourdevices.com\",\n \"mepn.com\",\n \"microsoft\",\n \"microsoft-int.com\",\n \"microsoft-ppe.com\",\n \"microsoft-sap-events.com\",\n \"microsoft-sbs-domains.com\",\n \"microsoft-smb.cn\",\n \"microsoft.az\",\n \"microsoft.be\",\n \"microsoft.by\",\n \"microsoft.ca\",\n \"microsoft.cat\",\n \"microsoft.ch\",\n \"microsoft.cl\",\n \"microsoft.com\",\n \"microsoft.com.akadns.net\",\n \"microsoft.com.nsatc.net\",\n \"microsoft.cz\",\n \"microsoft.de\",\n \"microsoft.dk\",\n \"microsoft.ee\",\n \"microsoft.es\",\n \"microsoft.eu\",\n \"microsoft.fi\",\n \"microsoft.ge\",\n \"microsoft.hu\",\n \"microsoft.io\",\n \"microsoft.is\",\n \"microsoft.it\",\n \"microsoft.jp\",\n \"microsoft.lt\",\n \"microsoft.lu\",\n \"microsoft.lv\",\n \"microsoft.md\",\n \"microsoft.net\",\n \"microsoft.pl\",\n \"microsoft.pt\",\n \"microsoft.red\",\n \"microsoft.ro\",\n \"microsoft.rs\",\n \"microsoft.ru\",\n \"microsoft.se\",\n \"microsoft.si\",\n \"microsoft.tv\",\n \"microsoft.ua\",\n \"microsoft.uz\",\n \"microsoft.vn\",\n \"microsoft365.com\",\n \"microsoftaccountguard.com\",\n \"microsoftads.com\",\n \"microsoftadvertising.com\",\n \"microsoftadvertisingregionalawards.com\",\n \"microsoftaffiliates.com\",\n \"microsoftapps.azurewebsites.net\",\n \"microsoftazuread-sso.com\",\n \"microsoftcloud.com\",\n \"microsoftcloudworkshop.com\",\n \"microsoftcommunitytraining.com\",\n \"microsoftemail.com\",\n \"microsoftestore.com.hk\",\n \"microsofthouse.com\",\n \"microsofthouse.net\",\n \"microsoftinternetsafety.net\",\n \"microsoftlatamaitour.com\",\n \"microsoftlinc.com\",\n \"microsoftonline-p.com\",\n \"microsoftonline-p.net\",\n \"microsoftonline.com\",\n \"microsoftpartnercommunity.com\",\n \"microsoftready.com\",\n \"microsoftsiteselection.com\",\n \"microsoftstore.com\",\n \"microsoftstore.com.cn\",\n \"microsoftstore.com.hk\",\n \"microsoftstream.com\",\n \"microsoftteams.com\",\n \"microsofttradein.com\",\n \"microsofttranslator.com\",\n \"microsoftuwp.com\",\n \"momentumms.com\",\n \"morphcharts.com\",\n \"mpnevolution.com\",\n \"ms-studiosmedia.com\",\n \"ms365surfaceoffer.com\",\n \"msa.akadns6.net\",\n \"msads.net\",\n \"msappproxy.net\",\n \"msauth.cn\",\n \"msauth.net\",\n \"msauthimages.net\",\n \"mschallenge2018.com\",\n \"msecnd.net\",\n \"msft.info\",\n \"msft.net\",\n \"msftauth.cn\",\n \"msftauth.net\",\n \"msftauthimages.net\",\n \"msftcenterone.cn\",\n \"msftconnecttest.com\",\n \"msfteducation.ca\",\n \"msftidentity.com\",\n \"msftnet.org\",\n \"msgamesresearch.com\",\n \"msidentity.com\",\n \"msignitechina.com\",\n \"msocdn.com\",\n \"msocsp.com\",\n \"msopentech.cn\",\n \"mspil.cn\",\n \"msra.cn\",\n \"mstea.ms\",\n \"msturing.org\",\n \"msudalosti.com\",\n \"msvevent.com\",\n \"mymicrosoft.com\",\n \"nextechafrica.net\",\n \"nxta.org\",\n \"oaspapps.com\",\n \"oaspapps.com.akadns.net\",\n \"onecollector.cloudapp.aria\",\n \"onecollector.cloudapp.aria.akadns.net\",\n \"onenote.com\",\n \"onenote.net\",\n \"onestore.ms\",\n \"onmicrosoft.com\",\n \"opticsforthecloud.net\",\n \"optimizely.com\",\n \"outingsapp.com\",\n \"outlook.cn\",\n \"outlook.com\",\n \"outlookgroups.ms\",\n \"outlookmobile.com\",\n \"passport.net\",\n \"phonefactor.net\",\n \"pixapp.net\",\n \"playfabapi.cn\",\n \"playfabcn.com\",\n \"powerappscdn.net\",\n \"powerautomate.com\",\n \"powerbi.com\",\n \"powershellgallery.com\",\n \"projectmurphy.net\",\n \"projectsangam.com\",\n \"pxt.io\",\n \"s-microsoft.com\",\n \"s-msft.com\",\n \"s-msn.com\",\n \"sfbassets.com\",\n \"sfbassets.net\",\n \"sfx.ms\",\n \"sharepoint.cn\",\n \"sharepoint.com\",\n \"sharepointonline.com\",\n \"skype\",\n \"staffhub.ms\",\n \"successwithteams.com\",\n \"surface.com\",\n \"svc.ms\",\n \"syncshop.cn\",\n \"sysinternals.com\",\n \"tailwindtraders.com\",\n \"techhub.ms\",\n \"tenor.com\",\n \"tfsallin.net\",\n \"trafficmanager.net\",\n \"translatetheweb.com\",\n \"unlocklimitlesslearning.com\",\n \"userpxt.io\",\n \"uservoice.com\",\n \"videobreakdown.com\",\n \"videoindexer.ai\",\n \"virtualearth.net\",\n \"vsallin.net\",\n \"wbd.ms\",\n \"what-fan.net\",\n \"windows.com\",\n \"windows.net\",\n \"windows-int.net\",\n \"windows-ppe.net\",\n \"windows.com\",\n \"windows.net\",\n \"windows.nl\",\n \"windows8.hk\",\n \"windowscommunity.net\",\n \"windowsmarketplace.com\",\n \"windowsphone-int.com\",\n \"windowsphone.com\",\n \"windowssearch.com\",\n \"windowsupdate.com\",\n \"winhec.com\",\n \"winhec.net\",\n \"yammer.com\",\n \"yammerusercontent.com\",\n \"g.akamaiedge.net\",\n \"a1158.g.akamai.net\",\n \"a122.dscg3.akamai.net\",\n \"a767.dscg3.akamai.net\",\n \"cs11.wpc.v0cdn.net\",\n \"cs9.wac.phicdn.net\",\n \"b.akamaiedge.net\",\n \"spoprod-a.akamaihd.net\",\n \"windows.com.akadns.net\",\n \"prod-video-cms-rt-microsoft-com.akamaized.net\",\n \"statics-marketingsites-eas-ms-com.akamaized.net\",\n \"statics-marketingsites-neu-ms-com.akamaized.net\",\n \"vip5.afdorigin-prod-am02.afdogw.com\",\n \"img-prod-cms-rt-microsoft-com.akamaized.net\",\n \"img-s-msn-com.akamaized.net\",\n \"mwf-service.akamaized.net\",\n \"officecdn-microsoft-com.akamaized.net\",\n \"statics-marketingsites-eus-ms-com.akamaized.net\",\n \"statics-marketingsites-wcus-ms-com.akamaized.net\"\n ],\n \"outbound\": \"Microsoft\"\n },\n {\n \"domain\": [\n \"apm.music.163.com\",\n \"apm3.music.163.com\",\n \"interface.music.163.com\",\n \"interface3.music.163.com\",\n \"music.163.com\"\n ],\n \"ip_cidr\": [\n \"101.71.154.241/32\",\n \"103.126.92.132/32\",\n \"103.126.92.133/32\",\n \"112.13.119.17/32\",\n \"112.13.122.1/32\",\n \"115.236.118.33/32\",\n \"115.236.121.1/32\",\n \"118.24.63.156/32\",\n \"193.112.159.225/32\",\n \"223.252.199.66/32\",\n \"223.252.199.67/32\",\n \"39.105.63.80/32\",\n \"45.254.48.1/32\",\n \"47.100.127.239/32\",\n \"59.111.160.195/32\",\n \"59.111.160.197/32\",\n \"59.111.181.35/32\",\n \"59.111.181.38/32\",\n \"59.111.181.60/32\"\n ],\n \"outbound\": \"Netease Music\"\n },\n {\n \"process_name\": [\n \"storedownloadd\",\n \"v2ray\",\n \"ss-local\",\n \"uubooster\",\n \"aria2c\",\n \"fdm\",\n \"folx\",\n \"nettransport\",\n \"qbittorrent\",\n \"qbittorrent-nox\",\n \"thunder\",\n \"transmission\",\n \"utorrent\",\n \"webtorrent\",\n \"webtorrent helper\"\n ],\n \"domain\": [\n \"aod.itunes.apple.com\",\n \"api.smoot.apple.cn\",\n \"appldnld.apple.com\",\n \"apptrailers.itunes.apple.com\",\n \"gs-loc-cn.apple.com\",\n \"iosapps.itunes.apple.com\",\n \"music.apple.com\",\n \"mvod.itunes.apple.com\",\n \"osxapps.itunes.apple.com\",\n \"supportdownload.apple.com\",\n \"swcdn.apple.com\",\n \"updates-http.cdn-apple.com\",\n \"safebrowsing.googleapis.com\",\n \"cm.steampowered.com\",\n \"ol.epicgames.com\",\n \"csgo.wmsj.cn\",\n \"dota2.wmsj.cn\",\n \"wmsjsteam.com\",\n \"dl.steam.clngaa.com\",\n \"dl.steam.ksyna.com\",\n \"gstore.val.manlaxy.com\",\n \"st.dl.bscstorage.net\",\n \"st.dl.eccdnx.com\",\n \"st.dl.pinyuncloud.com\",\n \"steampipe.steamcontent.tnkjmec.com\",\n \"steampowered.com.8686c.com\",\n \"steamstatic.com.8686c.com\",\n \"steambroadcast.akamaized.net\",\n \"steamcdn-a.akamaihd.net\",\n \"steamcommunity-a.akamaihd.net\",\n \"steamstore-a.akamaihd.net\",\n \"steamusercontent-a.akamaihd.net\",\n \"steamuserimages-a.akamaihd.net\",\n \"tesla-cdn.thron.cn\",\n \"tesla-cdn.thron.com\",\n \"uplaypc-s-ubisoft.cdn.ubi.com\"\n ],\n \"domain_suffix\": [\n \"ls.apple.com\",\n \"dl.google.com\",\n \"msftconnecttest.com\",\n \"dl.playstation.net\",\n \"steamcontent.com\",\n \"steamserver.net\",\n \"steamchina.com\",\n \"solarcity.com\",\n \"tesla.cn\",\n \"tesla.com\",\n \"tesla.com.cn\",\n \"teslamotors.cn\",\n \"teslamotors.com\",\n \"teslamotors.com.cn\",\n \"ts.la\",\n \"app-measurement.com\",\n \"xunlei.com\",\n \"audiences.me\",\n \"awesome-hd.me\",\n \"broadcasthe.net\",\n \"chdbits.co\",\n \"classix-unlimited.co.uk\",\n \"dmhy.best\",\n \"empornium.me\",\n \"gazellegames.net\",\n \"hdchina.org\",\n \"hdsky.me\",\n \"icetorrent.org\",\n \"jpopsuki.eu\",\n \"keepfrds.com\",\n \"madsrevolution.net\",\n \"m-team.cc\",\n \"nanyangpt.com\",\n \"ncore.cc\",\n \"open.cd\",\n \"ourbits.club\",\n \"passthepopcorn.me\",\n \"privatehd.to\",\n \"redacted.ch\",\n \"sandai.net\",\n \"springsunday.net\",\n \"tjupt.org\",\n \"totheglory.im\",\n \"smtp\"\n ],\n \"domain_keyword\": [\n \"epicgames\"\n ],\n \"ip_cidr\": [\n \"100.64.0.0/10\"\n ],\n \"outbound\": \"DIRECT\"\n },\n {\n \"domain\": [\n \"testflight.apple.com\",\n \"cdp.cloud.unity3d.com\",\n \"api.waqi.info\",\n \"aqi.aqicn.org\"\n ],\n \"domain_suffix\": [\n \"battle.net\",\n \"battlenet.com\",\n \"blizzard.com\",\n \"lin.ee\",\n \"line.me\",\n \"line.naver.jp\",\n \"line-apps.com\",\n \"line-cdn.net\",\n \"line-scdn.net\",\n \"nhncorp.jp\",\n \"riotcdn.net\",\n \"wr.pvp.net\",\n \"riotgames.com\",\n \"playstation.com\",\n \"playstation.net\",\n \"playstationnetwork.com\",\n \"api.amplitude.com\",\n \"app.smartmailcloud.com\",\n \"gate.hockeyapp.net\",\n \"smartmailcloud.com\",\n \"2o7.net\",\n \"4everproxy.com\",\n \"4shared.com\",\n \"4sqi.net\",\n \"9to5mac.com\",\n \"abpchina.org\",\n \"accountkit.com\",\n \"adblockplus.org\",\n \"adobe.com\",\n \"adobedtm.com\",\n \"aerisapi.com\",\n \"akamaihd.net\",\n \"airtable.com\",\n \"alfredapp.com\",\n \"allconnected.co\",\n \"amazon.co\",\n \"amazon.co.jp\",\n \"amazon.com\",\n \"amazonaws.com\",\n \"ampproject.com\",\n \"ampproject.net\",\n \"ampproject.org\",\n \"anaconda.com\",\n \"ancsconf.org\",\n \"android.com\",\n \"androidify.com\",\n \"android-x86.org\",\n \"angularjs.org\",\n \"anthonycalzadilla.com\",\n \"aol.com\",\n \"aolcdn.com\",\n \"apache.org\",\n \"api.mixpanel.com\",\n \"api.termius.com\",\n \"api.tiktokv.com\",\n \"api.urbandictionary.com\",\n \"apigee.com\",\n \"apk-dl.com\",\n \"apkpure.com\",\n \"appdownloader.net\",\n \"apple-dns.net\",\n \"appshopper.com\",\n \"arcgis.com\",\n \"archive.is\",\n \"archive.org\",\n \"archives.gov\",\n \"armorgames.com\",\n \"aspnetcdn.com\",\n \"async.be\",\n \"att.com\",\n \"avgle.com\",\n \"awsstatic.com\",\n \"azure.com\",\n \"azureedge.net\",\n \"azurewebsites.net\",\n \"badoo.com\",\n \"bandisoft.com\",\n \"bbtoystore.com\",\n \"bet365.com\",\n \"betvictor.com\",\n \"bigsound.org\",\n \"bintray.com\",\n \"bit.com\",\n \"bit.do\",\n \"bit.ly\",\n \"bitbucket.org\",\n \"bitcointalk.org\",\n \"bitshare.com\",\n \"bkrtx.com\",\n \"blog.com\",\n \"blogcdn.com\",\n \"blogger.com\",\n \"bloglovin.com\",\n \"blogsmithmedia.com\",\n \"blogspot.hk\",\n \"bloomberg.cn\",\n \"bloomberg.com\",\n \"books.com.tw\",\n \"boomtrain.com\",\n \"botanwang.com\",\n \"box.com\",\n \"box.net\",\n \"boxun.com\",\n \"cachefly.net\",\n \"cbc.ca\",\n \"cdn.angruo.com\",\n \"cdn.segment.com\",\n \"cdnst.net\",\n \"celestrak.com\",\n \"census.gov\",\n \"certificate-transparency.org\",\n \"chinadigitaltimes.net\",\n \"chinatimes.com\",\n \"chrome.com\",\n \"chromecast.com\",\n \"chromercise.com\",\n \"chromestatus.com\",\n \"chromium.org\",\n \"cl.ly\",\n \"clien.net\",\n \"cloud.cupronickel.goog\",\n \"cloudflare.com\",\n \"cloudfront.net\",\n \"cloudgarage.jp\",\n \"cloudmagic.com\",\n \"cmail19.com\",\n \"cnet.com\",\n \"cnn.com\",\n \"cocoapods.org\",\n \"comodoca.com\",\n \"crisp.chat\",\n \"culturedcode.com\",\n \"cygames.jp\",\n \"d.pr\",\n \"danilo.to\",\n \"daolan.net\",\n \"data-vocabulary.org\",\n \"dayone.me\",\n \"db.tt\",\n \"dcmilitary.com\",\n \"deja.com\",\n \"demdex.net\",\n \"deskconnect.com\",\n \"digisfera.com\",\n \"digitaltrends.com\",\n \"disconnect.me\",\n \"disq.us\",\n \"disqus.com\",\n \"disquscdn.com\",\n \"dler.io\",\n \"dnsimple.com\",\n \"docker.com\",\n \"doub.io\",\n \"dowjones.com\",\n \"dribbble.com\",\n \"droplr.com\",\n \"duckduckgo.com\",\n \"dueapp.com\",\n \"dw.com\",\n \"easybib.com\",\n \"economist.com\",\n \"edgecastcdn.net\",\n \"edgekey.net\",\n \"edgesuite.net\",\n \"engadget.com\",\n \"entrust.net\",\n \"eurekavpt.com\",\n \"evernote.com\",\n \"extmatrix.com\",\n \"eyny.com\",\n \"fabric.io\",\n \"fastly.net\",\n \"fastmail.com\",\n \"fc2.com\",\n \"feedburner.com\",\n \"feedly.com\",\n \"feedsportal.com\",\n \"firefox.com\",\n \"fiftythree.com\",\n \"firebaseio.com\",\n \"flexibits.com\",\n \"flickr.com\",\n \"flipboard.com\",\n \"flipkart.com\",\n \"flitto.com\",\n \"flurry.com\",\n \"freeopenproxy.com\",\n \"fubo.tv\",\n \"fullstory.com\",\n \"fzlm.net\",\n \"g.co\",\n \"gabia.net\",\n \"garena.com\",\n \"geni.us\",\n \"get.how\",\n \"getcloudapp.com\",\n \"getfoxyproxy.org\",\n \"getlantern.org\",\n \"getmdl.io\",\n \"getpricetag.com\",\n \"gfw.press\",\n \"ggpht.com\",\n \"ghostnoteapp.com\",\n \"ghcr.io\",\n \"git.io\",\n \"gitbook.com\",\n \"gitlab.com\",\n \"gitlab.io\",\n \"globalsign.com\",\n \"gmocloud.com\",\n \"gmodules.com\",\n \"go.com\",\n \"go.jp\",\n \"godaddy.com\",\n \"golang.org\",\n \"gongm.in\",\n \"goo.gl\",\n \"goodreaders.com\",\n \"goodreads.com\",\n \"gravatar.com\",\n \"gstatic.cn\",\n \"gstatic.com\",\n \"gunsamerica.com\",\n \"gvt0.com\",\n \"gvt1.com\",\n \"helpshift.com\",\n \"hitun.io\",\n \"hockeyapp.net\",\n \"homedepot.com\",\n \"hootsuite.com\",\n \"howtoforge.com\",\n \"i-cable.com\",\n \"iam.soy\",\n \"icoco.com\",\n \"icons8.com\",\n \"ift.tt\",\n \"ifttt.com\",\n \"imageshack.us\",\n \"img.ly\",\n \"imgur.com\",\n \"imore.com\",\n \"imtoken.fans\",\n \"ingress.com\",\n \"inoreader.com\",\n \"insder.co\",\n \"instapaper.com\",\n \"instructables.com\",\n \"io.io\",\n \"ip.sb\",\n \"ipaddress.com\",\n \"ipn.li\",\n \"is.gd\",\n \"ishowsapp.com\",\n \"issuu.com\",\n \"itgonglun.com\",\n \"itun.es\",\n \"ixquick.com\",\n \"j.mp\",\n \"javbus.com\",\n \"js.revsci.net\",\n \"jshint.com\",\n \"jtvnw.net\",\n \"justgetflux.com\",\n \"kakao.co.kr\",\n \"kakao.com\",\n \"kakaocdn.net\",\n \"kat.cr\",\n \"kenengba.com\",\n \"kik.com\",\n \"klip.me\",\n \"leancloud.com\",\n \"leetcode.com\",\n \"libsyn.com\",\n \"licdn.com\",\n \"lightboxcdn.com\",\n \"like.com\",\n \"linkedin.com\",\n \"linode.com\",\n \"lithium.com\",\n \"littlehj.com\",\n \"livefilestore.com\",\n \"llnwd.net\",\n \"localnetwork.uop\",\n \"logmein.com\",\n \"macid.co\",\n \"macromedia.com\",\n \"macrumors.com\",\n \"mangaup.jp\",\n \"manhuaren.com\",\n \"marketwatch.com\",\n \"mashable.com\",\n \"mathjax.org\",\n \"maven.org\",\n \"medium.com\",\n \"mega.co.nz\",\n \"mega.nz\",\n \"megaupload.com\",\n \"mindnode.com\",\n \"mixin.one\",\n \"mlssoccer.com\",\n \"mobile01.com\",\n \"modmyi.com\",\n \"moves-export.com\",\n \"mp3buscador.com\",\n \"mycnnews.com\",\n \"myfontastic.com\",\n \"mypikpak.com\",\n \"name.com\",\n \"nasa.gov\",\n \"ndr.de\",\n \"netdna-cdn.com\",\n \"newipnow.com\",\n \"nextmedia.com\",\n \"nicovideo.jp\",\n \"nih.gov\",\n \"nimg.jp\",\n \"nintendo.com\",\n \"nintendo.net\",\n \"notion.so\",\n \"novafile.com\",\n \"nrk.no\",\n \"nsstatic.net\",\n \"nssurge.com\",\n \"nyt.com\",\n \"nytimes.com\",\n \"nytimg.com\",\n \"nytstyle.com\",\n \"okx.com\",\n \"omnigroup.com\",\n \"ooyala.com\",\n \"openvpn.net\",\n \"openwrt.org\",\n \"orkut.com\",\n \"osha.gov\",\n \"osxdaily.com\",\n \"overcast.fm\",\n \"ow.ly\",\n \"paddle.com\",\n \"paddleapi.com\",\n \"panoramio.com\",\n \"parallels.com\",\n \"parse.com\",\n \"pdfexpert.com\",\n \"periscope.tv\",\n \"piaotian.net\",\n \"picacomic.com\",\n \"picasaweb.com\",\n \"pinboard.in\",\n \"ping.pe\",\n \"pinterest.com\",\n \"pixelmator.com\",\n \"pixiv.net\",\n \"pixnet.net\",\n \"playpcesor.com\",\n \"pokemon.com\",\n \"polymer-project.org\",\n \"popo.tw\",\n \"potato.im\",\n \"redd.it\",\n \"rthk.hk\",\n \"prfct.co\",\n \"proxfree.com\",\n \"psiphon3.com\",\n \"ptt.cc\",\n \"pubu.com.tw\",\n \"puffinbrowser.com\",\n \"pushbullet.com\",\n \"pushwoosh.com\",\n \"pximg.net\",\n \"quora.com\",\n \"quoracdn.net\",\n \"readingtimes.com.tw\",\n \"readmoo.com\",\n \"recaptcha.net\",\n \"reddit.com\",\n \"redditmedia.com\",\n \"redditstatic.com\",\n \"reuters.com\",\n \"rfi.fr\",\n \"rileyguide.com\",\n \"rime.im\",\n \"rsf.org\",\n \"sciencedaily.com\",\n \"sciencemag.org\",\n \"scribd.com\",\n \"search.com\",\n \"servebom.com\",\n \"sexinsex.net\",\n \"sfx.ms\",\n \"shadowsocks.org\",\n \"shadowverse.jp\",\n \"sharethis.com\",\n \"shazam.com\",\n \"shutterstock.com\",\n \"sidelinesnews.com\",\n \"simp.ly\",\n \"simplenote.com\",\n \"sketchappsources.com\",\n \"slack.com\",\n \"slack-edge.com\",\n \"slack-msgs.com\",\n \"slideshare.net\",\n \"smartdnsproxy.com\",\n \"smh.com.au\",\n \"snapchat.com\",\n \"sndcdn.com\",\n \"sockslist.net\",\n \"soundcloud.com\",\n \"sourceforge.net\",\n \"sowers.org.hk\",\n \"speedsmart.net\",\n \"spike.com\",\n \"squarespace.com\",\n \"ssa.gov\",\n \"sstatic.net\",\n \"st.luluku.pw\",\n \"stackoverflow.com\",\n \"starp2p.com\",\n \"startpage.com\",\n \"state.gov\",\n \"staticflickr.com\",\n \"storify.com\",\n \"stumbleupon.com\",\n \"sugarsync.com\",\n \"supermariorun.com\",\n \"surfeasy.com.au\",\n \"surge.run\",\n \"surrenderat20.net\",\n \"sydneytoday.com\",\n \"symauth.com\",\n \"symcb.com\",\n \"symcd.com\",\n \"t66y.com\",\n \"tablesgenerator.com\",\n \"tabtter.jp\",\n \"talk853.com\",\n \"talkboxapp.com\",\n \"talkonly.net\",\n \"tapbots.com\",\n \"tapbots.net\",\n \"teamviewer.com\",\n \"techcrunch.com\",\n \"technorati.com\",\n \"techsmith.com\",\n \"teddysun.com\",\n \"textnow.me\",\n \"thebobs.com\",\n \"theinitium.com\",\n \"thepiratebay.org\",\n \"theverge.com\",\n \"thewgo.org\",\n \"tiltbrush.com\",\n \"time.com\",\n \"timeinc.net\",\n \"tinder.com\",\n \"tiny.cc\",\n \"tinychat.com\",\n \"tinypic.com\",\n \"tmblr.co\",\n \"todoist.com\",\n \"togetter.com\",\n \"tokyocn.com\",\n \"tomshardware.com\",\n \"torcn.com\",\n \"torrentmac.net\",\n \"torrentprivacy.com\",\n \"torrentproject.se\",\n \"torrentz.eu\",\n \"tradingview.com\",\n \"traffichaus.com\",\n \"trakt.tv\",\n \"transparency.org\",\n \"trello.com\",\n \"trendsmap.com\",\n \"trulyergonomic.com\",\n \"trustasiassl.com\",\n \"tt-rss.org\",\n \"ttvnw.net\",\n \"tumblr.co\",\n \"tumblr.com\",\n \"turbobit.net\",\n \"tv.com\",\n \"tweetdeck.com\",\n \"tweetmarker.net\",\n \"twimg.co\",\n \"twitch.tv\",\n \"twitthat.com\",\n \"twtkr.com\",\n \"twttr.com\",\n \"txmblr.com\",\n \"typcn.com\",\n \"typekit.net\",\n \"typography.com\",\n \"ubertags.com\",\n \"ublock.org\",\n \"ubnt.com\",\n \"uchicago.edu\",\n \"udn.com\",\n \"ugo.com\",\n \"uhdwallpapers.org\",\n \"ulyssesapp.com\",\n \"unblockdmm.com\",\n \"unblocksites.co\",\n \"unpo.org\",\n \"unsplash.com\",\n \"untraceable.us\",\n \"uploaded.net\",\n \"uproxy.org\",\n \"upwork.com\",\n \"urchin.com\",\n \"urlparser.com\",\n \"us.to\",\n \"usertrust.com\",\n \"usgs.gov\",\n \"usma.edu\",\n \"uspto.gov\",\n \"ustream.tv\",\n \"v.gd\",\n \"v2ex.co\",\n \"v2ray.com\",\n \"van001.com\",\n \"vanpeople.com\",\n \"vansky.com\",\n \"vbstatic.co\",\n \"venchina.com\",\n \"venturebeat.com\",\n \"veoh.com\",\n \"verizonwireless.com\",\n \"viber.com\",\n \"vid.me\",\n \"videomega.tv\",\n \"vidinfo.org\",\n \"vimeo.com\",\n \"vimeocdn.com\",\n \"vimperator.org\",\n \"vine.co\",\n \"visibletweets.com\",\n \"viu.com\",\n \"vivaldi.com\",\n \"voachinese.com\",\n \"vocativ.com\",\n \"vox-cdn.com\",\n \"vpnaccount.org\",\n \"vpnbook.com\",\n \"vpngate.net\",\n \"vsco.co\",\n \"vultr.com\",\n \"vzw.com\",\n \"w.org\",\n \"w3schools.com\",\n \"wattpad.com\",\n \"web2project.net\",\n \"webfreer.com\",\n \"weblagu.com\",\n \"websnapr.com\",\n \"webtype.com\",\n \"webwarper.net\",\n \"wenxuecity.com\",\n \"westca.com\",\n \"westpoint.edu\",\n \"whatbrowser.org\",\n \"wikiwand.com\",\n \"wikileaks.info\",\n \"wikileaks.org\",\n \"wikileaks-forum.com\",\n \"wikimedia.org\",\n \"wikipedia.com\",\n \"wikipedia.org\",\n \"wn.com\",\n \"wordpress.com\",\n \"workflow.is\",\n \"workflowy.com\",\n \"worldcat.org\",\n \"wow.com\",\n \"wp.com\",\n \"wsj.com\",\n \"wsj.net\",\n \"wwitv.com\",\n \"x.com\",\n \"xanga.com\",\n \"xclient.info\",\n \"xda-developers.com\",\n \"xeeno.com\",\n \"xiti.com\",\n \"xn--ngstr-lra8j.com\",\n \"xteko.com\",\n \"xuite.net\",\n \"xvideos.com\",\n \"yahoo.com\",\n \"yahooapis.com\",\n \"yandex.com\",\n \"yasni.co.uk\",\n \"yastatic.net\",\n \"ycombinator.com\",\n \"yeeyi.com\",\n \"yesasia.com\",\n \"yes-news.com\",\n \"yidio.com\",\n \"yimg.com\",\n \"ying.com\",\n \"yorkbbs.ca\",\n \"youmaker.com\",\n \"yourlisten.com\",\n \"yoyo.org\",\n \"zacebook.com\",\n \"zalmos.com\",\n \"zaobao.com.sg\",\n \"zeutch.com\",\n \"zynamics.com\",\n \"1e100.net\",\n \"2mdn.net\",\n \"abc.xyz\",\n \"akamai.net\",\n \"appspot.com\",\n \"autodraw.com\",\n \"bandwagonhost.com\",\n \"blogblog.com\",\n \"chromeexperiments.com\",\n \"creativelab5.com\",\n \"crittercism.com\",\n \"culturalspot.org\",\n \"dartlang.org\",\n \"fb.com\",\n \"fb.me\",\n \"fbcdn.net\",\n \"fbsbx.com\",\n \"gcr.io\",\n \"gmail.com\",\n \"gosetsuden.jp\",\n \"gwtproject.org\",\n \"hackmd.io\",\n \"heroku.com\",\n \"html5rocks.com\",\n \"keyhole.com\",\n \"kobo.com\",\n \"kobobooks.com\",\n \"madewithcode.com\",\n \"material.io\",\n \"messenger.com\",\n \"netmarble.com\",\n \"nianticlabs.com\",\n \"pinimg.com\",\n \"proton.me\",\n \"pubnub.com\",\n \"scdn.co\",\n \"t.co\",\n \"tenor.com\",\n \"tensorflow.org\",\n \"toggleable.com\",\n \"torproject.org\",\n \"twimg.com\",\n \"twitpic.com\",\n \"unfiltered.news\",\n \"waveprotocol.org\",\n \"webmproject.org\",\n \"webrtc.org\",\n \"v2ex.com\",\n \"vikacg.com\",\n \"picjs.xyz\",\n \"wheel-size.cn\",\n \"chalungu.cn\"\n ],\n \"domain_keyword\": [\n \"tesla\",\n \"appledaily\",\n \"beetalk\",\n \"blogspot\",\n \"dropbox\",\n \"facebook\",\n \"github\",\n \"instagram\",\n \"twitter\",\n \"whatsapp\",\n \"google\",\n \"dlercloud\"\n ],\n \"ip_cidr\": [\n \"13.32.0.0/16\",\n \"13.33.0.0/16\",\n \"13.35.0.0/17\",\n \"18.184.0.0/15\",\n \"18.194.0.0/15\",\n \"18.208.0.0/13\",\n \"18.232.0.0/14\",\n \"52.200.0.0/13\",\n \"52.58.0.0/15\",\n \"52.74.0.0/16\",\n \"52.77.0.0/16\",\n \"52.84.0.0/15\",\n \"54.156.0.0/14\",\n \"54.226.0.0/15\",\n \"54.230.156.0/22\",\n \"54.93.0.0/16\",\n \"103.4.96.0/22\",\n \"129.134.0.0/17\",\n \"157.240.0.0/17\",\n \"173.252.64.0/19\",\n \"173.252.96.0/19\",\n \"179.60.192.0/22\",\n \"185.60.216.0/22\",\n \"204.15.20.0/22\",\n \"31.13.24.0/21\",\n \"31.13.64.0/18\",\n \"45.64.40.0/22\",\n \"66.220.144.0/20\",\n \"69.171.224.0/19\",\n \"69.63.176.0/20\",\n \"74.119.76.0/22\",\n \"173.194.0.0/16\",\n \"74.125.0.0/16\",\n \"1.201.0.0/24\",\n \"103.246.56.0/22\",\n \"103.27.148.0/22\",\n \"110.76.140.0/22\",\n \"113.61.104.0/22\",\n \"27.0.236.0/22\",\n \"103.2.28.0/22\",\n \"119.235.224.0/21\",\n \"119.235.232.0/23\",\n \"119.235.235.0/24\",\n \"119.235.236.0/23\",\n \"125.6.146.0/24\",\n \"125.6.149.0/24\",\n \"125.6.190.0/24\",\n \"125.209.208.0/20\",\n \"203.104.103.0/24\",\n \"203.104.128.0/20\",\n \"203.174.66.64/26\",\n \"203.174.77.0/24\",\n \"13.251.24.157/24\",\n \"13.251.41.203/24\",\n \"17.252.156.147/24\",\n \"17.252.157.26/24\",\n \"74.86.0.0/16\",\n \"75.126.0.0/16\",\n \"174.37.0.0/16\",\n \"208.43.0.0/16\"\n ],\n \"outbound\": \"Proxies\"\n },\n {\n \"domain_suffix\": [\n \"abchina.com\",\n \"abchina.com.cn\",\n \"boc.cn\",\n \"citicbank.com\",\n \"ecitic.com\",\n \"ecitic.net\",\n \"ccb.com\",\n \"ccb.com.cn\",\n \"cebbank.com\",\n \"cmbchina.com\",\n \"cmbimg.com\",\n \"cmbt.cn\",\n \"mbcloud.com\",\n \"icbc.com.cn\",\n \"pingan.com\",\n \"pingan.com.cn\",\n \"alphassl.com\",\n \"edu.cn\",\n \"p4pfile.com\",\n \"zmzfile.com\",\n \"sony.com\",\n \"sonyentertainmentnetwork.com\",\n \"10010.com\",\n \"10086.cn\",\n \"12306.cn\",\n \"12306.com\",\n \"126.net\",\n \"163.com\",\n \"189.cn\",\n \"360.cn\",\n \"360.com\",\n \"360buy.com\",\n \"360buyimg.com\",\n \"36kr.com\",\n \"51ym.me\",\n \"58.com\",\n \"8686c.com\",\n \"95516.com\",\n \"abercrombie.com\",\n \"acfun.tv\",\n \"adobesc.com\",\n \"aiaa.org\",\n \"air-matters.com\",\n \"air-matters.io\",\n \"aixifan.com\",\n \"alibaba.com\",\n \"alibabacloud.com\",\n \"alicdn.com\",\n \"alipay.com\",\n \"alipayobjects.com\",\n \"aliyun.com\",\n \"aliyuncs.com\",\n \"amap.com\",\n \"appshike.com\",\n \"appstore.com\",\n \"autonavi.com\",\n \"bababian.com\",\n \"baidu.com\",\n \"baidupcs.com\",\n \"bdimg.com\",\n \"bdstatic.com\",\n \"beatsbydre.com\",\n \"bochk.com\",\n \"caiyunapp.com\",\n \"ccgslb.com\",\n \"ccgslb.net\",\n \"chinacache.net\",\n \"chunbo.com\",\n \"chunboimg.com\",\n \"clouddn.com\",\n \"cloudsigma.com\",\n \"cloudxns.net\",\n \"cmct.tv\",\n \"cmfu.com\",\n \"chdbits.co\",\n \"cnlang.org\",\n \"coolapk.com\",\n \"cz88.net\",\n \"dct-cloud.com\",\n \"didialift.com\",\n \"digicert.com\",\n \"dler.cloud\",\n \"douban.com\",\n \"doubanio.com\",\n \"douyin.com\",\n \"douyu.com\",\n \"douyu.tv\",\n \"douyutv.com\",\n \"duokan.com\",\n \"duoshuo.com\",\n \"dytt8.net\",\n \"easou.com\",\n \"eudic.net\",\n \"ewqcxz.com\",\n \"feng.com\",\n \"fir.im\",\n \"frdic.com\",\n \"fresh-ideas.cc\",\n \"gameloft.com\",\n \"garmin.cn\",\n \"geetest.com\",\n \"godic.net\",\n \"goodread.com\",\n \"goofish.com\",\n \"gtimg.com\",\n \"haibian.com\",\n \"hao123.com\",\n \"haosou.com\",\n \"hdchina.org\",\n \"hdcmct.org\",\n \"hjfile.cn\",\n \"hkserversolution.com\",\n \"hollisterco.com\",\n \"hongxiu.com\",\n \"hujiang.com\",\n \"hxcdn.net\",\n \"icedropper.com\",\n \"iciba.com\",\n \"ifeng.com\",\n \"ifengimg.com\",\n \"images-amazon.com\",\n \"img4me.com\",\n \"ipapark.com\",\n \"ithome.com\",\n \"ixdzs.com\",\n \"jd.com\",\n \"jd.hk\",\n \"jianshu.com\",\n \"jianshu.io\",\n \"jianshuapi.com\",\n \"jiathis.com\",\n \"jomodns.com\",\n \"jsboxbbs.com\",\n \"knewone.com\",\n \"kuaidi100.com\",\n \"kugou.com\",\n \"lecloud.com\",\n \"lemicp.com\",\n \"letv.com\",\n \"letvcloud.com\",\n \"liyuans.com\",\n \"lizhi.io\",\n \"localizecdn.com\",\n \"lucifr.com\",\n \"luoo.net\",\n \"lxdns.com\",\n \"mai.tn\",\n \"meituan.com\",\n \"meizu.com\",\n \"metatrader4.com\",\n \"metatrader5.com\",\n \"mi.com\",\n \"miaopai.com\",\n \"miui.com\",\n \"miwifi.com\",\n \"mob.com\",\n \"moji.com\",\n \"moke.com\",\n \"mxhichina.com\",\n \"myqcloud.com\",\n \"myunlu.com\",\n \"ngabbs.com\",\n \"netease.com\",\n \"nfoservers.com\",\n \"nuomi.com\",\n \"ourbits.club\",\n \"ourdvs.com\",\n \"passthepopcorn.me\",\n \"pgyer.com\",\n \"pniao.com\",\n \"privatehd.to\",\n \"qbox.me\",\n \"qcloud.com\",\n \"qdaily.com\",\n \"qdmm.com\",\n \"qhimg.com\",\n \"qidian.com\",\n \"qihucdn.com\",\n \"qin.io\",\n \"qingmang.me\",\n \"qingmang.mobi\",\n \"qiniucdn.com\",\n \"qiniudn.com\",\n \"qq.com\",\n \"qqurl.com\",\n \"rarbg.to\",\n \"redacted.ch\",\n \"rrmj.tv\",\n \"ruguoapp.com\",\n \"sf-express.com\",\n \"sinaapp.com\",\n \"sinaimg.cn\",\n \"sinaimg.com\",\n \"smzdm.com\",\n \"snwx.com\",\n \"so.com\",\n \"sogou.com\",\n \"sogoucdn.com\",\n \"sohu.com\",\n \"soku.com\",\n \"soso.com\",\n \"sspai.com\",\n \"startssl.com\",\n \"suning.com\",\n \"symcd.com\",\n \"taobao.com\",\n \"tawk.link\",\n \"tawk.to\",\n \"tencent.com\",\n \"tencent-cloud.net\",\n \"tenpay.com\",\n \"tietuku.com\",\n \"tmall.com\",\n \"tmzvps.com\",\n \"trello.com\",\n \"trellocdn.com\",\n \"totheglory.im\",\n \"ttmeiju.com\",\n \"tudou.com\",\n \"udache.com\",\n \"umengcloud.com\",\n \"upaiyun.com\",\n \"upyun.com\",\n \"uxengine.net\",\n \"wandoujia.com\",\n \"weather.bjango.com\",\n \"webqxs.com\",\n \"wechat.com\",\n \"weibo.cn\",\n \"weibo.com\",\n \"weico.cc\",\n \"weiphone.com\",\n \"weiphone.net\",\n \"werewolf.53site.com\",\n \"wkcdn.com\",\n \"xdrig.com\",\n \"xhostfire.com\",\n \"xhscdn.com\",\n \"xiaohongshu.com\",\n \"xiaojukeji.com\",\n \"xiaomi.com\",\n \"xiaomi.net\",\n \"xiaomicp.com\",\n \"ximalaya.com\",\n \"xitek.com\",\n \"xmcdn.com\",\n \"xslb.net\",\n \"yach.me\",\n \"yeepay.com\",\n \"yhd.com\",\n \"yinxiang.com\",\n \"yixia.com\",\n \"ykimg.com\",\n \"youdao.com\",\n \"ysepay.cn\",\n \"ysepay.com\",\n \"yunjiasu-cdn.net\",\n \"zealer.com\",\n \"zgslb.net\",\n \"zhihu.com\",\n \"zhimg.com\",\n \"zimuzu.tv\",\n \"zmz002.com\",\n \"gov.cn\",\n \"cn\"\n ],\n \"domain_keyword\": [\n \"beplay\"\n ],\n \"domain\": [\n \"client.amplifi.com\",\n \"ip.bjango.com\"\n ],\n \"ip_cidr\": [\n \"185.188.32.0/24\",\n \"185.188.33.0/24\",\n \"185.188.34.0/24\",\n \"185.188.35.0/24\",\n \"182.254.116.0/24\",\n \"1.255.62.0/24\"\n ],\n \"outbound\": \"Domestic\"\n },\n {\n \"domain_keyword\": [\n \"apple.com.akadns.net\",\n \"icloud.com.akadns.net\"\n ],\n \"domain_suffix\": [\n \"aaplimg.com\",\n \"apple.co\",\n \"apple.com\",\n \"apple-cloudkit.com\",\n \"apple-mapkit.com\",\n \"appsto.re\",\n \"cdn-apple.com\",\n \"icloud.com\",\n \"icloud-content.com\",\n \"itunes.com\",\n \"me.com\",\n \"mzstatic.com\",\n \"apple.comscoreresearch.com\",\n \"apple.news\"\n ],\n \"ip_cidr\": [\n \"17.0.0.0/8\",\n \"63.92.224.0/19\",\n \"65.199.22.0/23\",\n \"139.178.128.0/18\",\n \"144.178.0.0/19\",\n \"144.178.36.0/22\",\n \"144.178.48.0/20\",\n \"192.35.50.0/24\",\n \"198.183.17.0/24\",\n \"205.180.175.0/24\"\n ],\n \"process_name\": [\n \"com.apple.geod\"\n ],\n \"outbound\": \"Apple\"\n },\n {\n \"domain_suffix\": [\n \"bitcointalk.org\",\n \"aex.com\",\n \"bibox.com\",\n \"bitfinex.com\",\n \"bithumb.com\",\n \"bitmex.com\",\n \"bitstamp.net\",\n \"bittrex.com\",\n \"bybit.com\",\n \"coinbase.com\",\n \"coincheck.com\",\n \"coinone.co.kr\",\n \"gemini.com\",\n \"korbit.co.kr\",\n \"kraken.com\",\n \"kucoin.com\",\n \"liquid.com\",\n \"poloniex.com\",\n \"bitbank.cc\",\n \"bitcoin.org\",\n \"bitquick.co\",\n \"btcbox.co.jp\",\n \"cex.io\",\n \"dogecoin.com\",\n \"paxful.com\",\n \"tether.to\",\n \"dydx.exchange\",\n \"solana.com\",\n \"avax.network\",\n \"optimism.io\",\n \"arbitrum.io\",\n \"poly.network\",\n \"zkscan.io\",\n \"zksync.io\",\n \"boba.network\",\n \"binance.cc\",\n \"binance.cloud\",\n \"binance.com\",\n \"binance.im\",\n \"binance.me\",\n \"binance.us\",\n \"bnappzh.co\",\n \"bnappzh.com\",\n \"bnbstatic.com\",\n \"bntrace.com\",\n \"binance.charity\",\n \"binance.co\",\n \"binance.info\",\n \"binance.net\",\n \"binance.org\",\n \"binance.vision\",\n \"binanceapi.com\",\n \"binancezh.be\",\n \"binancezh.biz\",\n \"binancezh.cc\",\n \"binancezh.co\",\n \"binancezh.com\",\n \"binancezh.info\",\n \"binancezh.ink\",\n \"binancezh.kim\",\n \"binancezh.link\",\n \"binancezh.live\",\n \"binancezh.mobi\",\n \"binancezh.net\",\n \"binancezh.pro\",\n \"binancezh.sh\",\n \"binancezh.top\",\n \"bnappzh.mobi\",\n \"bsc.getblock.io\",\n \"bscscan.com\",\n \"hbabit.com\",\n \"hbfile.net\",\n \"huobi.com\",\n \"huobi.me\",\n \"huobi.pro\",\n \"huobi.sc\",\n \"huobiasia.vip\",\n \"huobigroup.com\",\n \"huobitoken.com\",\n \"heco-scan.com\",\n \"hecoview.com\",\n \"hbfile.net\",\n \"huobi.br.com\",\n \"bitderiv.com\",\n \"hecochain.com\",\n \"huobi.ws\",\n \"huobi.ug\",\n \"huobi.co.ma\",\n \"huobi.br.com\",\n \"okex.com\",\n \"okx.com\",\n \"asproex.com\",\n \"asproexapi.com\",\n \"bitflyer.com\",\n \"bitflyer.jp\",\n \"bisq.io\",\n \"bisq.network\",\n \"bitsquare.io\",\n \"coinone.co.kr\",\n \"coinonecore.com\",\n \"coinonecorp.com\",\n \"devcon.org\",\n \"ethereum.foundation\",\n \"ethereum.org\",\n \"etherscan.io\",\n \"nansen.ai\",\n \"ethgasstation.info\",\n \"watchtheburn.com\",\n \"flashbots.net\",\n \"cryptofees.info\",\n \"etherscan.io\",\n \"ethereum-magicians.org\",\n \"vitalik.ca\",\n \"ethfans.org\",\n \"ethereum.cn\",\n \"ethereum.stackexchange.com\",\n \"etherscan.com\",\n \"parity.io\",\n \"ethernodes.org\",\n \"localbitcoins.com\",\n \"localbitcoinschain.com\",\n \"zb.app\",\n \"zb.com\",\n \"zb.io\",\n \"zb.live\",\n \"aicoin.com\",\n \"aimoon.com\",\n \"coingecko.com\",\n \"coinmarketcap.com\",\n \"glassnode.com\",\n \"coinmetrics.io\",\n \"tokenview.com\",\n \"oklink.com\",\n \"blockchair.com\",\n \"intotheblock.com\",\n \"bytetree.com\",\n \"coin.dance\",\n \"defieye.io\",\n \"duneanalytics.com\",\n \"tokenterminal.com\",\n \"dapp.review\",\n \"dappradar.com\",\n \"stateofthedapps.com\",\n \"thegraph.com\",\n \"debank.com\",\n \"vfat.tools\",\n \"loanscan.io\",\n \"defirate.com\",\n \"defipulse.com\",\n \"apy999.com\",\n \"defieye.io\",\n \"dextools.io\",\n \"tradingview.com\",\n \"dcabtc.com\",\n \"chainalysis.com\",\n \"cryptoquant.com\",\n \"viewbase.com\",\n \"bitcoinity.org\",\n \"cryptocompare.com\",\n \"coincodex.com\",\n \"cointrendz.com\",\n \"coincheckup.com\",\n \"thetie.io\",\n \"cryptorank.io\",\n \"tradeblock.com\",\n \"nyctale.io\",\n \"dovemetrics.com\",\n \"cryptorank.io\",\n \"icodrops.com\",\n \"chainbroker.io\",\n \"crunchbase.com\",\n \"defillama.com\",\n \"coinowo.com\",\n \"earni.fi\",\n \"dropsearn.com\",\n \"bitcoin.it\",\n \"bitcoinmagazine.com\",\n \"blockchain.com\",\n \"tronscan.org\",\n \"btc.com\",\n \"f2pool.com\",\n \"cbeci.org\",\n \"digiconomist.net\",\n \"1ml.com\",\n \"bitcoinvisuals.com\",\n \"crypto51.app\",\n \"masternodes.online\",\n \"bitnodes.earn.com\",\n \"poolin.com\",\n \"ethermine.org\",\n \"ewapool.net\",\n \"ftx.com\",\n \"opensea.io\",\n \"nftscan.com\",\n \"makersplace.com\",\n \"nonfungible.com\",\n \"cryptoslam.io\",\n \"cryptoart.io\",\n \"nftcalendar.io\",\n \"nftgo.io\",\n \"filecoin.io\",\n \"docs.lotu.sh\",\n \"ipfs.io\",\n \"docs.ipfs.io\",\n \"discuss.ipfs.io\",\n \"eos.io\",\n \"developers.eos.io\",\n \"block.one\",\n \"eostracker.io\",\n \"eosflare.io\",\n \"eospark.com\",\n \"bloks.io\",\n \"lightning.engineering\",\n \"lightning.community\",\n \"acinq.co\",\n \"1ml.com\",\n \"tokenpocket.pro\",\n \"token.im\",\n \"phantom.app\",\n \"tronlink.org\",\n \"myetherwallet.com\",\n \"jaxx.io\",\n \"trustwalletapp.com\",\n \"gate.ac\",\n \"gate.io\",\n \"mexc.com\",\n \"sushi.com\",\n \"uniswap.org\",\n \"sunswap.com\",\n \"traderjoexyz.com\",\n \"raydium.io\",\n \"synthetix.io\",\n \"aave.com\",\n \"compound.finance\",\n \"makerdao.com\",\n \"wbtc.network\",\n \"pancakeswap.finance\",\n \"pancakeswap.com\",\n \"mdex.co\",\n \"mdex.one\",\n \"mdex.com\",\n \"mdex.me\",\n \"1inch.io\"\n ],\n \"process_name\": [\n \"binance.exe\",\n \"huobi.exe\",\n \"okx.exe\"\n ],\n \"domain_keyword\": [\n \"binance\",\n \"huobi\",\n \"okx\",\n \"metamask\"\n ],\n \"domain\": [\n \"token-api.metaswap.codefi.network\",\n \"min-api.cryptocompare.com\"\n ],\n \"outbound\": \"Crypto\"\n },\n {\n \"domain_suffix\": [\n \"discord.com\",\n \"discord.gg\",\n \"discord.media\",\n \"discordapp.com\",\n \"discordapp.net\",\n \"discordstatus.com\"\n ],\n \"outbound\": \"Discord\"\n },\n {\n \"domain\": [\n \"mtalk.google.com\",\n \"mtalk4.google.com\",\n \"mtalk-staging.google.com\",\n \"mtalk-dev.google.com\",\n \"alt1-mtalk.google.com\",\n \"alt2-mtalk.google.com\",\n \"alt3-mtalk.google.com\",\n \"alt4-mtalk.google.com\",\n \"alt5-mtalk.google.com\",\n \"alt6-mtalk.google.com\",\n \"alt7-mtalk.google.com\",\n \"alt8-mtalk.google.com\",\n \"android.apis.google.com\",\n \"device-provisioning.googleapis.com\",\n \"firebaseinstallations.googleapis.com\"\n ],\n \"ip_cidr\": [\n \"64.233.177.188/32\",\n \"64.233.186.188/32\",\n \"64.233.187.188/32\",\n \"64.233.188.188/32\",\n \"64.233.189.188/32\",\n \"74.125.23.188/32\",\n \"74.125.24.188/32\",\n \"74.125.28.188/32\",\n \"74.125.127.188/32\",\n \"74.125.137.188/32\",\n \"74.125.203.188/32\",\n \"74.125.204.188/32\",\n \"74.125.206.188/32\",\n \"108.177.125.188/32\",\n \"142.250.4.188/32\",\n \"142.250.10.188/32\",\n \"142.250.31.188/32\",\n \"142.250.96.188/32\",\n \"172.217.194.188/32\",\n \"172.217.218.188/32\",\n \"172.217.219.188/32\",\n \"172.253.63.188/32\",\n \"172.253.122.188/32\",\n \"173.194.175.188/32\",\n \"173.194.218.188/32\",\n \"209.85.233.188/32\"\n ],\n \"outbound\": \"Google FCM\"\n },\n {\n \"domain_suffix\": [\n \"augment.com\",\n \"augmentcode.com\",\n \"ai.com\",\n \"chatgpt.com\",\n \"openai.com\",\n \"cdn.oaistatic.com\",\n \"oaiusercontent.com\",\n \"anthropic.com\",\n \"claude.ai\",\n \"claudeusercontent.com\",\n \"diabrowser.engineering\",\n \"windsurf.com\",\n \"codeium.com\",\n \"codeiumdata.com\",\n \"chorus.sh\",\n \"githubcopilot.com\",\n \"microsoftonline.com\",\n \"cursor.sh\",\n \"dify.ai\",\n \"apis.google.com\",\n \"bard.google.com\",\n \"gemini.google.com\",\n \"deepmind.com\",\n \"deepmind.google\",\n \"generativelanguage.googleapis.com\",\n \"geller-pa.googleapis.com\",\n \"proactivebackend-pa.googleapis.com\",\n \"aistudio.google.com\",\n \"makersuite.google.com\",\n \"generativeai.google\",\n \"notebooklm.google\",\n \"notebooklm.google.com\",\n \"x.ai\",\n \"grok.com\",\n \"groq.com\",\n \"clipdrop.co\",\n \"jasper.ai\",\n \"meta.ai\",\n \"openart.ai\",\n \"openrouter.ai\",\n \"perplexity.ai\",\n \"poe.com\",\n \"sora.com\",\n \"zed.dev\"\n ],\n \"domain\": [\n \"chat.openai.com.cdn.cloudflare.net\",\n \"openaiapi-site.azureedge.net\",\n \"openaicom-api-bdcpf8c6d2e9atf6.z01.azurefd.net\",\n \"openaicomproductionae4b.blob.core.windows.net\",\n \"production-openaicom-storage.azureedge.net\",\n \"o33249.ingest.sentry.io\",\n \"gateway.ai.cloudflare.com\",\n \"copilot.microsoft.com\",\n \"api.github.com\",\n \"ai.google.dev\",\n \"alkalicore-pa.clients6.google.com\",\n \"waa-pa.clients6.google.com\",\n \"apple-relay.apple.com\",\n \"apple-relay.cloudflare.com\",\n \"guzzoni.smoot.apple.com\",\n \"sora-cdn.oaistatic.com\"\n ],\n \"domain_keyword\": [\n \"alkalimakersuite-pa.clients6.google.com\"\n ],\n \"outbound\": \"AI Suite\"\n },\n {\n \"domain_suffix\": [\n \"bh3.com\",\n \"hoyolab.com\",\n \"hoyoverse.com\",\n \"mihayo.com\",\n \"mihoyo.com\",\n \"miyoushe.com\",\n \"yuanshen.com\"\n ],\n \"outbound\": \"miHoYo\"\n },\n {\n \"geoip\": \"cn\",\n \"outbound\": \"Domestic\"\n }\n ],\n \"auto_detect_interface\": true,\n \"final\": \"Others\"\n },\n}', 'json', '{}', '2025-08-12 23:30:10.016', '2025-08-15 22:01:10.801'); -INSERT INTO `subscribe_application` (`id`, `name`, `icon`, `description`, `scheme`, `user_agent`, `is_default`, `subscribe_template`, `output_format`, `download_link`, `created_at`, `updated_at`) VALUES (5, 'Surge', '', '', 'surge:///install-config?url=${encodeURIComponent(url)}', 'Surge', 0, '{{- $GiB := 1073741824.0 -}}\n{{- $used := printf \"%.2f\" (divf (add (.UserInfo.Download | default 0 | float64) (.UserInfo.Upload | default 0 | float64)) $GiB) -}}\n{{- $total := printf \"%.2f\" (divf (.UserInfo.Traffic | default 0 | float64) $GiB) -}}\n\n{{- $exp := \"\" -}}\n{{- if or (kindIs \"int\" .UserInfo.ExpiredAt) (kindIs \"int64\" .UserInfo.ExpiredAt) (kindIs \"float64\" .UserInfo.ExpiredAt) -}}\n {{- $exp = (date \"2006-01-02 15:04:05\" (unixEpoch .UserInfo.ExpiredAt)) -}}\n{{- else -}}\n {{- $expStr := printf \"%v\" .UserInfo.ExpiredAt -}}\n {{- if regexMatch `^[0-9]+$` $expStr -}}\n {{- $ts := $expStr | int64 -}}\n {{- $sec := ternary (divf ($ts | float64) 1000.0 | int64) $ts (ge (len $expStr) 13) -}}\n {{- $exp = (date \"2006-01-02 15:04:05\" (unixEpoch $sec)) -}}\n {{- else if regexMatch `^[0-9]{4}-[0-9]{2}-[0-9]{2}$` $expStr -}}\n {{- $exp = (printf \"%s 00:00:00\" $expStr) -}}\n {{- else if regexMatch `^[0-9]{4}-[0-9]{2}-[0-9]{2}[ T][0-9]{2}:[0-9]{2}:[0-9]{2}$` $expStr -}}\n {{- $exp = (replace $expStr \"T\" \" \") -}}\n {{- else if regexMatch `^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}.*` $expStr -}}\n {{- $t := mustToDate \"2006-01-02T15:04:05Z07:00\" $expStr -}}\n {{- $exp = (date \"2006-01-02 15:04:05\" $t) -}}\n {{- else -}}\n {{- $exp = $expStr -}}\n {{- end -}}\n{{- end -}}\n\n#!MANAGED-CONFIG {{ .UserInfo.SubscribeURL }} interval=86400\n# {{ .SiteName }} - {{ .SubscribeName }} - Traffic: {{ $used }} GiB/{{ $total }} GiB | Expires: {{ $exp }}\n\n[General]\nloglevel = notify\n\ndns-server = system,119.29.29.29,223.5.5.5,223.6.6.6\nskip-proxy = localhost,*.local,*.ts.net,captive.apple.com,e.crashlytics.com,sequoia.apple.com,seed-sequoia.siri.apple.com,www.baidu.com,passenger.t3go.cn,yunbusiness.ccb.com,wxh.wo.cn,gate.lagou.com,www.abchina.com.cn,login-service.mobile-bank.psbc.com,mobile-bank.psbc.com,10.0.0.0/8,100.64.0.0/10,127.0.0.1/32,169.254.0.0/16,172.16.0.0/12,192.168.0.0/16,192.168.122.1/32,193.168.0.1/32,224.0.0.0/4,240.0.0.0/4,255.255.255.255/32,::1/128,fc00::/7,fd00::/8,fe80::/10,ff00::/8,2001::/32,2001:db8::/32,2002::/16,::ffff:0:0:0:0/1,::ffff:128:0:0:0/1\n# tun-excluded-routes = 192.168.0.0/16,10.0.0.0/8,172.16.0.0/12\n# tun-included-routes = 192.168.1.12/32\nexclude-simple-hostnames = true\n\nalways-real-ip = *.lan,*.direct,cable.auth.com,*.msftconnecttest.com,*.msftncsi.com,network-test.debian.org,detectportal.firefox.com,resolver1.opendns.com,*.srv.nintendo.net,*.stun.playstation.net,xbox.*.microsoft.com,*.xboxlive.com,stun.*,global.turn.twilio.com,global.stun.twilio.com,app.yinxiang.com,injections.adguard.org,local.adguard.org,cable.auth.com,localhost.*.qq.com,localhost.*.weixin.qq.com,*.logon.battlenet.com.cn,*.logon.battle.net,*.blzstatic.cn,music.163.com,*.music.163.com,*.126.net,musicapi.taihe.com,music.taihe.com,songsearch.kugou.com,trackercdn.kugou.com,*.kuwo.cn,api-jooxtt.sanook.com,api.joox.com,joox.com,y.qq.com,*.y.qq.com,streamoc.music.tc.qq.com,mobileoc.music.tc.qq.com,isure.stream.qqmusic.qq.com,dl.stream.qqmusic.qq.com,aqqmusic.tc.qq.com,amobile.music.tc.qq.com,*.xiami.com,*.music.migu.cn,music.migu.cn,proxy.golang.org,*.mcdn.bilivideo.cn,*.cmpassport.com,id6.me,open.e.189.cn,opencloud.wostore.cn,id.mail.wo.cn,mdn.open.wo.cn,hmrz.wo.cn,nishub1.10010.com,enrichgw.10010.com,*.wosms.cn,*.jegotrip.com.cn,*.icitymobile.mobi,*.pingan.com.cn,*.cmbchina.com,*.10099.com.cn,*.microdone.cn,pool.ntp.org,*.pool.ntp.org,ntp.*.com,time.*.com,ntp?.*.com,time?.*.com,time.*.gov,time.*.edu.cn,*.ntp.org.cn,PDC._msDCS.*.*,DC._msDCS.*.*,GC._msDCS.*.*\n\nhijack-dns = 8.8.8.8:53,8.8.4.4:53,1.1.1.1:53,1.0.0.1:53\n\nhttp-listen = 0.0.0.0\nsocks5-listen = 0.0.0.0\nwifi-access-http-port = 8888\nwifi-access-socks5-port = 8889\n\nexternal-controller-access = dler@0.0.0.0:6170\n\ninternet-test-url = http://wifi.vivo.com.cn/generate_204\nproxy-test-url = http://cp.cloudflare.com/generate_204\ntest-timeout = 3\n\nallow-wifi-access = true\nshow-error-page-for-reject = true\nuse-default-policy-if-wifi-not-primary = false\nipv6 = false\n\n[Proxy]\nDirect = direct\nBlock = reject\n# Traffic: {{ $used }} GiB/{{ $total }} GiB | Expires: {{ $exp }}\n\n{{- range $proxy := .Proxies }}\n {{- if eq $proxy.Type \"shadowsocks\" }}\n{{ $proxy.Name }} = ss, {{ $proxy.Host }}, {{ $proxy.Port }}, encrypt-method={{ default \"aes-128-gcm\" $proxy.Method }}, password={{ $.UserInfo.Password }}{{- if $proxy.ServerKey }}, server-key={{ $proxy.ServerKey }}{{- end }}{{- if $proxy.Network }}, obfs={{ $proxy.Network }}, obfs-host={{ $proxy.SNI | default $proxy.Host }}{{- end }}, udp-relay=true, no-error-alert=true, tfo=true\n {{- else if eq $proxy.Type \"trojan\" }}\n{{ $proxy.Name }} = trojan, {{ $proxy.Host }}, {{ $proxy.Port }}, password={{ $.UserInfo.Password }}{{- if eq $proxy.Network \"ws\" }}, ws=true, ws-path={{ $proxy.Path | default \"/\" }}{{- if $proxy.Host }}, ws-headers=\"Host:{{ $proxy.Host }}\"{{- end }}{{- else if eq $proxy.Network \"grpc\" }}, grpc=true, grpc-service-name={{ $proxy.ServiceName | default \"grpc\" }}{{- end }}{{- if $proxy.SNI }}, sni={{ $proxy.SNI }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify={{ $proxy.AllowInsecure }}{{- end }}{{- if $proxy.Fingerprint }}, fingerprint={{ $proxy.Fingerprint }}{{- end }}, udp-relay=true, no-error-alert=true, tfo=true\n {{- else if eq $proxy.Type \"vless\" }}\n{{ $proxy.Name }} = vless, {{ $proxy.Host }}, {{ $proxy.Port }}, username={{ $proxy.ServerKey }}{{- if eq $proxy.Network \"ws\" }}, ws=true, ws-path={{ $proxy.Path | default \"/\" }}{{- if $proxy.Host }}, ws-headers=\"Host:{{ $proxy.Host }}\"{{- end }}{{- else if eq $proxy.Network \"grpc\" }}, grpc=true, grpc-service-name={{ $proxy.ServiceName | default \"grpc\" }}{{- end }}{{- if $proxy.SNI }}, sni={{ $proxy.SNI }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify={{ $proxy.AllowInsecure }}{{- end }}{{- if $proxy.Flow }}, flow={{ $proxy.Flow }}{{- end }}, udp-relay=true, no-error-alert=true, tfo=true\n {{- else if eq $proxy.Type \"vmess\" }}\n{{ $proxy.Name }} = vmess, {{ $proxy.Host }}, {{ $proxy.Port }}, username={{ $proxy.ServerKey }}{{- if eq $proxy.Network \"ws\" }}, ws=true, ws-path={{ $proxy.Path | default \"/\" }}{{- if $proxy.Host }}, ws-headers=\"Host:{{ $proxy.Host }}\"{{- end }}{{- else if eq $proxy.Network \"grpc\" }}, grpc=true, grpc-service-name={{ $proxy.ServiceName | default \"grpc\" }}{{- end }}{{- if or $proxy.SNI $proxy.Fingerprint $proxy.AllowInsecure }}, tls=true{{- end }}{{- if $proxy.SNI }}, sni={{ $proxy.SNI }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify={{ $proxy.AllowInsecure }}{{- end }}{{- if $proxy.Fingerprint }}, fingerprint={{ $proxy.Fingerprint }}{{- end }}, udp-relay=true, no-error-alert=true, tfo=true\n {{- else if or (eq $proxy.Type \"hysteria2\") (eq $proxy.Type \"hy2\") }}\n{{ $proxy.Name }} = hysteria2, {{ $proxy.Host }}, {{ $proxy.Port }}, password={{ $.UserInfo.Password }}{{- if $proxy.SNI }}, sni={{ $proxy.SNI }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify={{ $proxy.AllowInsecure }}{{- end }}{{- if $proxy.ObfsPassword }}, obfs=salamander, obfs-password={{ $proxy.ObfsPassword }}{{- end }}{{- if $proxy.HopPorts }}, ports={{ $proxy.HopPorts }}{{- end }}{{- if $proxy.HopInterval }}, hop-interval={{ $proxy.HopInterval }}{{- end }}, udp-relay=true, no-error-alert=true\n {{- else if eq $proxy.Type \"tuic\" }}\n{{ $proxy.Name }} = tuic, {{ $proxy.Host }}, {{ $proxy.Port }}, uuid={{ $proxy.ServerKey }}, password={{ $.UserInfo.Password }}{{- if $proxy.SNI }}, sni={{ $proxy.SNI }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify={{ $proxy.AllowInsecure }}{{- end }}{{- if $proxy.DisableSNI }}, disable-sni={{ $proxy.DisableSNI }}{{- end }}{{- if $proxy.ReduceRtt }}, reduce-rtt={{ $proxy.ReduceRtt }}{{- end }}{{- if $proxy.UDPRelayMode }}, udp-relay-mode={{ $proxy.UDPRelayMode }}{{- end }}{{- if $proxy.CongestionController }}, congestion-controller={{ $proxy.CongestionController }}{{- end }}, udp-relay=true, no-error-alert=true\n {{- else if eq $proxy.Type \"wireguard\" }}\n{{ $proxy.Name }} = wireguard, {{ $proxy.Host }}, {{ $proxy.Port }}, private-key={{ $proxy.ServerKey }}, public-key={{ $proxy.RealityPublicKey }}{{- if $proxy.Path }}, preshared-key={{ $proxy.Path }}{{- end }}{{- if $proxy.RealityServerAddr }}, ip={{ $proxy.RealityServerAddr }}{{- end }}{{- if $proxy.RealityServerPort }}, ipv6={{ $proxy.RealityServerPort }}{{- end }}, udp-relay=true, no-error-alert=true\n {{- else }}\n{{ $proxy.Name }} = {{ $proxy.Type }}, {{ $proxy.Host }}, {{ $proxy.Port }}, udp-relay=true, no-error-alert=true, tfo=true\n {{- end }}\n{{- end }}\n\n\n[Proxy Group]\n# {{ .SiteName }} - {{ .SubscribeName }} - Traffic: {{ $used }} GiB/{{ $total }} GiB | Expires: {{ $exp }}\nProxy = select, Auto - UrlTest, Direct{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}\nDomestic = select, Direct, Proxy{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}\nOthers = select, Proxy, Direct{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}\nAdBlock = select, Block, Direct, Proxy\nHTTPDNS = select, Direct, Block, Proxy\nAI Suite = select, Proxy, Direct{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}\nNetflix = select, Proxy, Direct{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}\nDisney Plus = select, Proxy, Direct{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}\nYouTube = select, Proxy, Direct{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}\nMax = select, Proxy, Direct{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}\nSpotify = select, Proxy, Direct{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}\nCN Mainland TV = select, Direct, Proxy{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}\nAsian TV = select, Proxy, Direct{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}\nGlobal TV = select, Proxy, Direct{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}\nApple = select, Direct, Proxy{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}\nApple TV = select, Proxy, Direct{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}\nTelegram = select, Proxy, Direct{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}\nGoogle FCM = select, Proxy, Direct{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}\nCrypto = select, Proxy, Direct{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}\nDiscord = select, Proxy, Direct{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}\nPayPal = select, Direct, Proxy{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}\nMicrosoft = select, Proxy, Direct{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}\nScholar = select, Direct, Proxy{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}\nSpeedtest = select, Proxy, Direct{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}\nSteam = select, Proxy, Direct{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}\nTikTok = select, Proxy, Direct{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}\nmiHoYo = select, Direct, Proxy{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}\nAuto - UrlTest = url-test{{- range $proxy := .Proxies }}, {{ $proxy.Name }}{{- end }}, url = http://cp.cloudflare.com/generate_204, interval = 3600, tolerance = 100\n\n\n[Rule]\nRULE-SET,https://raw.githubusercontent.com/tindy2013/subconverter/master/base/rules/LocalAreaNetwork.list,DIRECT,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Scholar.list,Scholar,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/AdBlock.list,AdBlock,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/Netflix.list,Netflix,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/Spotify.list,Spotify,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/Disney%20Plus.list,Disney,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/YouTube.list,YouTube,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/YouTube%20Music.list,YouTube,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/Max.list,Max,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/Bilibili.list,CN Mainland TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/IQ.list,CN Mainland TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/IQIYI.list,CN Mainland TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/Letv.list,CN Mainland TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/MOO.list,CN Mainland TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/Netease%20Music.list,CN Mainland TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/Tencent%20Video.list,CN Mainland TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/Youku.list,CN Mainland TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/WeTV.list,CN Mainland TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/master/Surge/Surge%203/Provider/Media/Apple%20Music.list,Apple TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/master/Surge/Surge%203/Provider/Media/Apple%20News.list,Apple TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/master/Surge/Surge%203/Provider/Media/Apple%20TV.list,Apple TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/Abema%20TV.list,Asian TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/Bahamut.list,Asian TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/Fox%2B.list,Asian TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/Hulu%20Japan.list,Asian TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/Japonx.list,Asian TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/JOOX.list,Asian TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/KKBOX.list,Asian TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/KKTV.list,Asian TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/Line%20TV.list,Asian TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/MOO.list,Asian TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/myTV%20SUPER.list,Asian TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/Niconico.list,Asian TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/ViuTV.list,Asian TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/ABC.list,Global TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/Amazon.list,Global TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/BBC%20iPlayer.list,Global TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/DAZN.list,Global TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/Discovery%20Plus.list,Global TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/encoreTVB.list,Global TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/F1%20TV.list,Global TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/Fox%20Now.list,Global TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/Hulu.list,Global TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/Pandora.list,Global TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/PBS.list,Global TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/Pornhub.list,Global TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/Soundcloud.list,Global TV,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Telegram.list,Telegram,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Steam.list,Steam,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Speedtest.list,Speedtest,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/PayPal.list,PayPal,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Microsoft.list,Microsoft,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Media/Netease%20Music.list,Netease Music,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Special.list,DIRECT,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Proxy.list,Proxies,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Domestic.list,Domestic,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Apple.list,Apple,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Crypto.list,Crypto,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Discord.list,Discord,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/Google%20FCM.list,Google FCM,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/AI%20Suite.list,AI Suite,update-interval=86400\nRULE-SET,https://raw.githubusercontent.com/dler-io/Rules/main/Surge/Surge%203/Provider/miHoYo.list,miHoYo,update-interval=86400\nGEOIP,CN,Domestic\nFINAL,Others\n\n[Host]\nip6-localhost = ::1\nip6-loopback = ::1\ntaobao.com = server:223.6.6.6\n*.taobao.com = server:223.6.6.6\ntmall.com = server:223.6.6.6\n*.tmall.com = server:223.6.6.6\njd.com = server:119.29.29.29\n*.jd.com = server:119.28.28.28\n*.qq.com = server:119.28.28.28\n*.tencent.com = server:119.28.28.28\n*.alicdn.com = server:223.5.5.5\naliyun.com = server:223.5.5.5\n*.aliyun.com = server:223.5.5.5\nweixin.com = server:119.28.28.28\n*.weixin.com = server:119.28.28.28\nbilibili.com = server:119.29.29.29\n*.bilibili.com = server:119.29.29.29\n*.hdslb.com = server:119.29.29.29\n163.com = server:119.29.29.29\n*.163.com = server:119.29.29.29\n126.com = server:119.29.29.29\n*.126.com = server:119.29.29.29\n*.126.net = server:119.29.29.29\n*.127.net = server:119.29.29.29\n*.netease.com = server:119.29.29.29\nmi.com = server:119.29.29.29\n*.mi.com = server:119.29.29.29\nxiaomi.com = server:119.29.29.29\n*.xiaomi.com = server:119.29.29.29\nrouterlogin.net = server:system\n_hotspot_.m2m = server:system\nrouter.asus.com = server:system\nhotspot.cslwifi.com = server:system\namplifi.lan = server:system\n*.lan = server:system\n*.local = server:system\n*.arpa = server:system\n\n[URL Rewrite]\n\"(^https?:\\/\\/app\\.biliintl\\.com\\/(x\\/)?(intl|dm|reply|history|v\\d/msgfeed).+)(&s_locale=zh-Hans_[A-Z]{2})(.+)(&sim_code=\\d+)(.+)\" $1&s_locale=zh-Hans_PH$6&sim_code=51503$8 header\n\"(^https?:\\/\\/passport\\.biliintl\\.com\\/x\\/intl\\/passport-login\\/.+)(&s_locale=zh-Hans_[A-Z]{2})(.+)(&sim_code=\\d+)(.+)\" $1&s_locale=zh-Hans_PH$35&sim_code=51503$5 header\n\"^http:\\/\\/(www.)?aicoin\\.cn\\/$\" https://www.aicoin.com/ 302\n\"^http?:\\/\\/(www.)?jd\\.com\\/\" https://www.jd.com/ 302\n\"^https?:\\/\\/(ditu|maps).google\\.cn\" https://maps.google.com 302\n\"^https?:\\/\\/(www.)?(betterzipcn|betterzip)\\.(com|net)\\/\" https://macitbetter.com/ 302\n\"^https?:\\/\\/(www.)?(g|google)\\.cn\" https://www.google.com 302\n\"^https?:\\/\\/(www.)?(mycleanmymac|xitongqingli)\\.com\\/\" https://macpaw.com/ 302\n\"^https?:\\/\\/(www.)?abbyychina\\.com\\/\" https://www.abbyy.cn/ 302\n\"^https?:\\/\\/(www.)?alienskins\\.cn\\/\" https://exposure.software/ 302\n\"^https?:\\/\\/(www.)?anydeskchina.cn/\" https://anydesk.com/zhs 302\n\"^https?:\\/\\/(www.)?bartender\\.cc\\/\" https://www.macbartender.com/ 302\n\"^https?:\\/\\/(www.)?beyondcompare\\.cc\\/\" https://www.scootersoftware.com/ 302\n\"^https?:\\/\\/(www.)?bingdianhuanyuan\\.cn\\/\" https://www.faronics.com/zh-hans/products/deep-freeze 302\n\"^https?:\\/\\/(www.)?chemdraw\\.com\\.cn\\/\" https://www.perkinelmer.com.cn/ 302\n\"^https?:\\/\\/(www.)?codesoftchina\\.com\\/\" https://www.teklynx.com/ 302\n\"^https?:\\/\\/(www.)?coreldrawchina\\.com\\/\" https://www.coreldraw.com/cn/ 302\n\"^https?:\\/\\/(www.)?crossoverchina\\.com\\/\" https://www.codeweavers.com/ 302\n\"^https?:\\/\\/(www.)?dongmansoft\\.com\\/\" https://www.udongman.cn/ 302\n\"^https?:\\/\\/(www.)?earmasterchina\\.cn\\/\" https://www.earmaster.com/ 302\n\"^https?:\\/\\/(www.)?easyrecoverychina\\.com\\/\" https://www.ontrack.com/ 302\n\"^https?:\\/\\/(www.)?ediuschina\\.com\\/\" https://www.grassvalley.com/ 302\n\"^https?:\\/\\/(www.)?firefox\\.com\\.cn\\/(download\\/)?$\" https://www.mozilla.org/zh-CN/firefox/new/ 302\n\"^https?:\\/\\/(www.)?flstudiochina\\.com\\/\" https://www.image-line.com/ 302\n\"^https?:\\/\\/(www.)?folxchina\\.cn\\/\" https://mac.eltima.com/cn/download-manager.html 302\n\"^https?:\\/\\/(www.)?formysql\\.com\\/\" https://www.navicat.com.cn/ 302\n\"^https?:\\/\\/(www.)?guitarpro\\.cc\\/\" https://www.guitar-pro.com/ 302\n\"^https?:\\/\\/(www.)?huishenghuiying\\.com\\.cn\\/\" https://www.coreldraw.com/cn/ 302\n\"^https?:\\/\\/(www.)?hypeapp\\.cn\\/\" https://tumult.com/hype/ 302\n\"^https?:\\/\\/(www.)?iconworkshop\\.cn\\/\" https://www.axialis.com/ 302\n\"^https?:\\/\\/(www.)?idmchina\\.net\\/\" https://www.internetdownloadmanager.com/ 302\n\"^https?:\\/\\/(www.)?ign\\.xn--fiqs8s\\/\" http://cn.ign.com/ccpref/us 302\n\"^https?:\\/\\/(www.)?imazingchina\\.com\\/\" https://imazing.com/zh 302\n\"^https?:\\/\\/(www.)?imindmap\\.cc\\/\" https://www.ayoa.com/previously-imindmap/ 302\n\"^https?:\\/\\/(www.)?jihehuaban\\.com\\.cn\\/\" https://www.chartwellyorke.com/sketchpad/x24795.html 302\n\"^https?:\\/\\/(www.)?kingdeecn\\.cn\\/\" http://www.kingdee.com/ 302\n\"^https?:\\/\\/(www.)?logoshejishi\\.com\" https://www.sothink.com/product/logo-design-software/ 302\n\"^https?:\\/\\/(www.)?luping\\.net\\.cn\\/\" https://www.techsmith.com/ 302\n\"^https?:\\/\\/(www.)?mathtype\\.cn\\/\" https://www.dessci.com/ 302\n\"^https?:\\/\\/(www.)?mi\\.com\\/\" https://www.mi.com/ 302\n\"^https?:\\/\\/(www.)?mindmanager\\.(cc|cn)\\/\" https://www.mindjet.com/cn/ 302\n\"^https?:\\/\\/(www.)?mindmapper\\.cc\\/\" https://www.mindmapper.com/ 302\n\"^https?:\\/\\/(www.)?nicelabel\\.cc\\/\" https://www.nicelabel.com/zh/ 302\n\"^https?:\\/\\/(www.)?ntfsformac\\.cc\\/\" https://china.paragon-software.com/home-mac/ntfs-for-mac/ 302\n\"^https?:\\/\\/(www.)?officesoftcn\\.com\\/\" https://www.microsoft.com/zh-cn/microsoft-365 302\n\"^https?:\\/\\/(www.)?overturechina\\.com\\/\" https://sonicscores.com/ 302\n\"^https?:\\/\\/(www.)?passwordrecovery\\.cn\\/\" https://cn.elcomsoft.com/aopr.html 302\n\"^https?:\\/\\/(www.)?pdfexpert\\.cc\\/\" https://pdfexpert.com/zh 302\n\"^https?:\\/\\/(www.)?photozoomchina\\.com\\/\" https://www.benvista.com/ 302\n\"^https?:\\/\\/(www.)?shankejingling\\.com\\/\" https://www.sothink.com/product/flashdecompiler/ 302\n\"^https?:\\/\\/(www.)?suning\\.com\\/\" https://suning.com/ 302\n\"^https?:\\/\\/(www.)?taobao\\.com\\/\" https://taobao.com/ 302\n\"^https?:\\/\\/(www.)?vegaschina\\.cn\\/\" https://www.vegascreativesoftware.com/ 302\n\"^https?:\\/\\/(www.)?xshellcn\\.com\\/\" https://www.netsarang.com/zh/xshell/ 302\n\"^https?:\\/\\/(www.)?yhd\\.com\\/\" https://yhd.com/ 302\n\"^https?:\\/\\/(www.)?yuanchengxiezuo\\.com\\/\" https://www.teamviewer.com/ 302\n\"^https?:\\/\\/(www.)?zbrushcn.com/\" https://pixologic.com/ 302\n\"^https?:\\/\\/cn\\.ultraiso\\.net\\/\" https://cn.ezbsystems.com/ultraiso/ 302\n\"^https?:\\/\\/hypersnap\\.mairuan\\.com\\/\" https://www.keyshot.com/ 302\n\"^https?:\\/\\/logoshejishi\\.mairuan\\.com\\/\" https://www.sothink.com/product/logo-design-software/ 302\n\"^https?:\\/\\/you\\.163\\.com\\/\" https://you.163.com/ 302\n\n# > Wiki\n# ^https:\\/\\/zh.(m.)?wikipedia.org\\/zh(-\\w*)?(?=\\/) https:\\/\\/www.wikiwand.com\\/zh$2 302\n# ^https:\\/\\/(\\w*).(m.)?wikipedia.org\\/wiki https:\\/\\/www.wikiwand.com\\/$1 302\n\n\n\n# Advertising Block\n# > NOMO\n^https:\\/\\/nomo.dafork.com\\/api\\/v3\\/iap\\/ios_product_list https:\\/\\/files.catbox.moe\\/fgmkpy.json 302\n\n# > Other\n^https?:\\/\\/cfg.m.ttkvod.com\\/mobile\\/ttk_mobile_1.8.txt http:\\/\\/ogtre5vp0.bkt.clouddn.com\\/Static\\/TXT\\/ttk_mobile_1.8.txt header\n^https?:\\/\\/cnzz.com\\/ http:\\/\\/ogtre5vp0.bkt.clouddn.com\\/background.png? header\n^https?:\\/\\/m.qu.la\\/stylewap\\/js\\/wap.js http:\\/\\/ogtre5vp0.bkt.clouddn.com\\/qu_la_wap.js 302\n^https?:\\/\\/m.yhd.com\\/1\\/\\? http:\\/\\/m.yhd.com\\/1\\/?adbock= 302\n^https?:\\/\\/n.mark.letv.com\\/m3u8api\\/ http:\\/\\/burpsuite.applinzi.com\\/Interface header\n^https?:\\/\\/static.m.ttkvod.com\\/static_cahce\\/index\\/index.txt http:\\/\\/ogtre5vp0.bkt.clouddn.com\\/Static\\/TXT\\/index.txt header\n^https?:\\/\\/www.iqshw.com\\/d\\/js\\/m http:\\/\\/burpsuite.applinzi.com\\/Interface header\n^https?:\\/\\/www.iqshw.com\\/d\\/js\\/m http:\\/\\/rewrite.websocket.site:10\\/Other\\/Static\\/JS\\/Package.js? header\n\n# > Anti_ISP_JavaScript_Injection\n^https?:\\/\\/c.minisplat.cn - reject\n^https?:\\/\\/c1.minisplat.cn - reject\n^https?:\\/\\/cache.changjingyi.cn - reject\n^https?:\\/\\/cache.gclick.cn - reject\n\n# > Anti_ISP_Safari_Baidu_CPM_Hijack\n^https?:\\/\\/m.coolaiy.com\\/b.php - reject\n^https?:\\/\\/www.babyye.com\\/b.php - reject\n^https?:\\/\\/www.gwv7.com\\/b.php - reject\n^https?:\\/\\/www.likeji.net\\/b.php - reject\n\n# > ChinaRailcom\n^https?:\\/\\/211.98.70.226:8080\\/ - reject\n^https?:\\/\\/211.98.71.195:8080\\/ - reject\n^https?:\\/\\/211.98.71.196:8080\\/ - reject\n\n# > Foodie\n^https?:\\/\\/cdn\\.fivecdm\\.com\\/cr\\/ - reject\n\n# > 腾讯\n^https?:\\/\\/.+.mp4\\?cdncode=.+&sdtfrom=v3004 - reject\n^https?:\\/\\/.+\\/hls.cache.p4p\\/ - reject\n^https?:\\/\\/.+\\/music\\/common\\/upload\\/t_splash_info - reject\n^https?:\\/\\/.+\\/omts.tc.qq.com\\/ - reject\n^https?:\\/\\/.+\\/tips\\/fcgi-bin\\/fcg_get_advert - reject\n^https?:\\/\\/.+\\/variety.tc.qq.com\\/ - reject\n^https?:\\/\\/.+\\/vlive.qqvideo.tc.qq.com\\/ - reject\n^https?:\\/\\/3gimg.qq.com\\/tencentMapTouch\\/app\\/activity\\/ - reject\n^https?:\\/\\/api5.futunn.com\\/ad\\/ - reject\n^https?:\\/\\/bla.gtimg.com\\/qqlive\\/\\d{6}.+.png - reject\n^https?:\\/\\/imgcache.qq.com\\/qqlive\\/ - reject\n^https?:\\/\\/lives.l.qq.com\\/livemsg\\?sdtfrom= - reject\n^https?:\\/\\/mmgr.gtimg.com\\/gjsmall\\/qiantu\\/upload\\/ - reject\n^https?:\\/\\/mp.weixin.qq.com\\/mp\\/(ad_complaint|ad_video|advertisement_report|getappmsgad|report) - reject\n^https?:\\/\\/mtteve.beacon.qq.com\\/analytics - reject\n^https?:\\/\\/qt.qq.com\\/lua\\/mengyou\\/get_splash_screen_info - reject\n^https?:\\/\\/r.inews.qq.com\\/(adsBlacklist|getBannerAds|getFullScreenPic|getNewsRemoteConfig|getQQNewsRemoteConfig|searchHotCatList|upLoadLoc) - reject\n^https?:\\/\\/r.inews.qq.com\\/getSplash\\?apptype=ios&startarticleid=&__qnr= - reject\n^https?:\\/\\/splashqqlive.gtimg.com\\/website\\/\\d{6} - reject\n^https?:\\/\\/ssl.kohsocialapp.qq.com:10001\\/game\\/buttons - reject\n^https?:\\/\\/szextshort.weixin.qq.com\\/cgi-bin\\/mmoc-bin\\/ad\\/ - reject\n^https?:\\/\\/vv.video.qq.com\\/getvmind\\? - reject\n^https?:\\/\\/y.gtimg.cn\\/music\\/common\\/upload\\/targeted_ads - reject\n\n# > 新浪\n^https?:\\/\\/api.weibo.cn\\/2\\/statuses\\/extend\\?gsid= - reject\n^https?:\\/\\/edit.sinaapp.com\\/ua\\?t=adv - reject\n^https?:\\/\\/free.sinaimg.cn\\/u1.img.mobile.sina.cn - reject\n^https?:\\/\\/simg.s.weibo.com\\/.+_ios\\d{2}.gif - reject\n^https?:\\/\\/storage.wax.weibo.com\\/\\w+.(png|jpg|mp4) - reject\n^https?:\\/\\/u1.img.mobile.sina.cn\\/public\\/files\\/image\\/\\d{3}x\\d{2,4}.+(png|jpg|mp4) - reject\n\n# > 优酷\n^https?:\\/\\/(iyes|(api|hd).mobile).youku.com\\/(adv|common\\/v3\\/hudong\\/new) - reject\n^https?:\\/\\/.+.mp4\\?ccode=0902 - reject\n^https?:\\/\\/.+.mp4\\?sid= - reject\n^https?:\\/\\/ad.api.3g.youku.com - reject\n^https?:\\/\\/api.appsdk.soku.com\\/(bg|tag)\\/r - reject\n^https?:\\/\\/api.k.sohu.com\\/api\\/channel\\/ad\\/ - reject\n^https?:\\/\\/api.mobile.youku.com\\/layout\\/search\\/hot\\/word - reject\n^https?:\\/\\/m.youku.com\\/video\\/libs\\/iwt.js - reject\n^https?:\\/\\/pic.k.sohu.com\\/img8\\/wb\\/tj\\/ - reject\n^https?:\\/\\/r.l.youku.com\\/rec_at_click - reject\n^https?:\\/\\/r1.ykimg.com\\/\\w{30,35}.jpg - reject\n^https?:\\/\\/r1.ykimg.com\\/material\\/.+\\/\\d{3,4}-\\d{4} - reject\n^https?:\\/\\/r1.ykimg.com\\/material\\/.+\\/\\d{6}\\/\\d{4}\\/ - reject\n^https?:\\/\\/ups.youku.com\\/(.*)needad=1& ^https?:\\/\\/ups.youku.com\\/$1needad=0& 302\n^https?:\\/\\/vali.cp31.ott.cibntv.net\\/youku - reject\n\n# > 网易\n^https?:\\/\\/.+.127.net\\/ad - reject\n^https?:\\/\\/.+\\/eapi\\/(ad|evenet|log)\\/ - reject\n^https?:\\/\\/c.m.163.com\\/nc\\/gl\\/ - reject\n^https?:\\/\\/client.mail.163.com\\/apptrack\\/confinfo\\/searchMultiAds - reject\n^https?:\\/\\/dsp-impr2.youdao.com\\/adload.s\\? - reject\n^https?:\\/\\/g1.163.com\\/madfeedback - reject\n^https?:\\/\\/img1.126.net\\/.+dpi=\\w{7,8} - reject\n^https?:\\/\\/img1.126.net\\/channel14\\/ - reject\n^https?:\\/\\/interface.music.163.com\\/eapi\\/ad\\/ - reject\n^https?:\\/\\/mimg.127.net\\/external\\/smartpop-manger.min.js - reject\n^https?:\\/\\/nex.163.com\\/q - reject\n^https?:\\/\\/oimage([a-z])([0-9]).ydstatic.com\\/.+?&product=adpublish - reject\n^https?:\\/\\/sp.kaola.com\\/api\\/openad - reject\n^https?:\\/\\/support.you.163.com\\/xhr\\/boot\\/getBootMedia.json - reject\n\n# > 知乎\n^https?:\\/\\/api.zhihu.com\\/ab\\/api - reject\n^https?:\\/\\/api.zhihu.com\\/ad-style-service - reject\n^https?:\\/\\/api.zhihu.com\\/app_config - reject\n^https?:\\/\\/api.zhihu.com\\/appview\\/api\\/v4\\/answers.+recommendations - reject\n^https?:\\/\\/api.zhihu.com\\/banner - reject\n^https?:\\/\\/api.zhihu.com\\/launch - reject\n^https?:\\/\\/api.zhihu.com\\/market\\/popover - reject\n^https?:\\/\\/api.zhihu.com\\/real_time - reject\n^https?:\\/\\/api.zhihu.com\\/search\\/preset_words - reject\n^https?:\\/\\/api.zhihu.com\\/search\\/top_search - reject\n^https?:\\/\\/api.zhihu.com\\/zst\\/events - reject\n^https?:\\/\\/www.zhihu.com\\/api\\/v4\\/community-ad\\/ - reject\n^https?:\\/\\/www.zhihu.com\\/terms\\/privacy\\/confirm - reject\n\n# > 追书神器\n^https?:\\/\\/(api|b).zhuishushenqi.com\\/advert - reject\n^https?:\\/\\/api.zhuishushenqi.com\\/notification\\/shelfMessage - reject\n^https?:\\/\\/api.zhuishushenqi.com\\/recommend - reject\n^https?:\\/\\/api.zhuishushenqi.com\\/splashes\\/ios - reject\n^https?:\\/\\/api01pbmp.zhuishushenqi.com\\/gameAdvert - reject\n# > Upgrade\n^https?:\\/\\/api.zhuishushenqi.com\\/user\\/bookshelf-updated - reject\n^https?:\\/\\/itunes.apple.com\\/lookup\\?id=575826903 - reject\n\n# > 爱奇艺\n^https?:\\/\\/.+\\/cdn\\/qiyiapp\\/\\d{8}\\/.+&dis_dz= - reject\n^https?:\\/\\/.+\\/cdn\\/qiyiapp\\/\\d{8}\\/.+&z=\\w - reject\n^https?:\\/\\/.+\\/videos\\/other\\/ - reject\n^https?:\\/\\/iface2.iqiyi.com\\/fusion\\/3.0\\/fusion_switch - reject\n\n# > 搜狐\n^https?:\\/\\/agn.aty.sohu.com\\/m? - reject\n^https?:\\/\\/api.k.sohu.com\\/api\\/news\\/adsense - reject\n^https?:\\/\\/hui.sohu.com\\/predownload2\\/? - reject\n^https?:\\/\\/m.aty.sohu.com\\/openload? - reject\n^https?:\\/\\/mbl.56.com\\/config\\/v1\\/common\\/config.union.ios.do? - reject\n^https?:\\/\\/mmg.aty.sohu.com\\/mqs? - reject\n^https?:\\/\\/mmg.aty.sohu.com\\/pvlog? - reject\n^https?:\\/\\/photocdn.sohu.com\\/tvmobilemvms - reject\n^https?:\\/\\/pic.k.sohu.com\\/img8\\/wb\\/tj\\/ - reject\n^https?:\\/\\/s.go.sohu.com\\/adgtr\\/\\?gbcode= - reject\n\n# > 阿里巴巴\n^https?:\\/\\/acs\\.m\\.taobao\\.com\\/gw\\/mtop\\.alibaba\\.advertisementservice\\.getadv\\/ - reject\n\n# > 百度\n(ps|sv|offnavi|newvector|ulog.imap|newloc)(.map)?.(baidu|n.shifen).com - reject\n^https?:\\/\\/afd.baidu.com\\/afd\\/entry - reject\n^https?:\\/\\/als.baidu.com\\/clog\\/clog - reject\n^https?:\\/\\/baichuan.baidu.com\\/rs\\/adpmobile\\/launch - reject\n^https?:\\/\\/bj.bcebos.com\\/fc-feed\\/0\\/pic\\/ - reject\n^https?:\\/\\/c.tieba.baidu.com\\/\\w+\\/\\w+\\/(sync|newRnSync|newlog|mlog) - reject\n^https?:\\/\\/c.tieba.baidu.com\\/c\\/p\\/img\\?src= - reject\n^https?:\\/\\/c.tieba.baidu.com\\/c\\/s\\/logtogether\\?cmd= - reject\n^https?:\\/\\/fcvbjbcebos.baidu.com\\/.+.mp4 - reject\n^https?:\\/\\/gss0.bdstatic.com\\/.+\\/static\\/wiseindex\\/img\\/bd_red_packet.png - reject\n^https?:\\/\\/issuecdn.baidupcs.com\\/issue\\/netdisk\\/guanggao\\/ - reject\n^https?:\\/\\/sm.domobcdn.com\\/ugc\\/\\w\\/ - reject\n^https?:\\/\\/tb1.bdstatic.com\\/tb\\/cms\\/ngmis\\/adsense\\/*.jpg - reject\n^https?:\\/\\/tb2.bdstatic.com\\/tb\\/mobile\\/spb\\/widget\\/jump - reject\n^https?:\\/\\/update.pan.baidu.com\\/statistics - reject\n^https?:\\/\\/wapwenku.baidu.com\\/view\\/fengchao\\/ - reject\n^https?:\\/\\/wapwenku.baidu.com\\/view\\/fengchaoTwojump\\/ - reject\n^https?:\\/\\/wenku.baidu.com\\/shifen\\/ - reject\n\n# > 百度地图\n^https?:\\/\\/newclient\\.map\\.baidu\\.com\\/client\\/crossmarketing - reject\n^https?:\\/\\/newclient\\.map\\.baidu\\.com\\/client\\/phpui.*qt=hw - reject\n^https?:\\/\\/newclient\\.map\\.baidu\\.com\\/client\\/phpui.*qt=rgc - reject\n^https?:\\/\\/newclient\\.map\\.baidu\\.com\\/client\\/phpui2\\/\\?qt=ads - reject\n^https?:\\/\\/newclient\\.map\\.baidu\\.com\\/client\\/usersystem\\/home\\/dynamic - reject\n\n# > 百度贴吧\n^https?:\\/\\/c.tieba.baidu.com\\/c\\/s\\/splashSchedule - reject\n^https?:\\/\\/cover.baidu.com\\/cover\\/page\\/dspSwitchAds\\/ - reject\n\n# > 百度网盘\n^https?:\\/\\/pan\\.baidu\\.com\\/act\\/api\\/activityentry - reject\n^https?:\\/\\/pan\\.baidu\\.com\\/act\\/v\\d\\/(bchannel|welfare)\\/list - reject\n^https?:\\/\\/pan\\.baidu\\.com\\/rest\\/\\d\\.\\d\\/pcs\\/ad - reject\n^https?:\\/\\/issuecdn\\.baidupcs\\.com\\/issue\\/netdisk\\/guanggao - reject\n\n# > 财联社\n^https?:\\/\\/api3\\.cls\\.cn\\/v1\\/boot\\/ad\\? - reject\n\n# > 菜鸟\n ^https?:\\/\\/cn-acs\\.m\\.cainiao\\.com\\/gw\\/mtop\\.cainiao\\.guoguo\\.nbnetflow\\.ads\\.(show|mshow)\\.cn\\/ - reject\n\n# > Jump\n^https?:\\/\\/switch\\.jumpvg\\.com\\/jump\\/(getlaunchad|recommend\\/ad_conf) - reject\n\n# > 墨迹天气\n^https?:\\/\\/ad.api.moji.com\\/ad\\/log\\/stat - reject\n^https?:\\/\\/ast.api.moji.com\\/assist\\/ad\\/moji\\/stat - reject\n^https?:\\/\\/cdn.moji.com\\/adlink\\/avatarcard - reject\n^https?:\\/\\/cdn.moji.com\\/adlink\\/common - reject\n^https?:\\/\\/cdn.moji.com\\/adlink\\/splash\\/ - reject\n^https?:\\/\\/cdn.moji.com\\/advert\\/ - reject\n^https?:\\/\\/cdn2.moji002.com\\/webpush\\/ad2\\/ - reject\n^https?:\\/\\/fds.api.moji.com\\/card\\/recommend - reject\n^https?:\\/\\/show.api.moji.com\\/json\\/showcase\\/getAll - reject\n^https?:\\/\\/stat.moji.com - reject\n^https?:\\/\\/storage.360buyimg.com\\/kepler-app - reject\n^https?:\\/\\/ugc.moji001.com\\/sns\\/json\\/profile\\/get_unread - reject\n\n# > 小米\n^https?:\\/\\/api.m.mi.com\\/v1\\/app\\/start - reject\n^https?:\\/\\/api.jr.mi.com\\/v1\\/adv\\/ - reject\n^https?:\\/\\/home\\.mi\\.com\\/cgi-op\\/api\\/v1\\/recommendation\\/(banner|myTab|openingBanner) - reject\n^https?:\\/\\/shop-api\\.retail\\.mi\\.com\\/mtop\\/navi\\/skywheel\\/mishop\\/splash - reject\n^https?:\\/\\/shopapi\\.io\\.mi\\.com\\/mtop\\/mf\\/resource\\/homePage\\/pageConfig - reject\n\n# > 中国电信\n^https?:\\/\\/image1.chinatelecom-ec.com\\/images\\/.+\\/\\d{13}.jpg - reject\n\n# > 中国联通\n^https?:\\/\\/m.client.10010.com\\/mobileService\\/(activity|customer)\\/(accountListData|get_client_adv|get_startadv) - reject\n^https?:\\/\\/m.client.10010.com\\/uniAdmsInterface\\/(getHomePageAd|getWelcomeAd) - reject\n^https?:\\/\\/m1.ad.10010.com\\/noticeMag\\/images\\/imageUpload\\/2\\d{3} - reject\n^https?:\\/\\/res.mall.10010.cn\\/mall\\/common\\/js\\/fa.js?referer= - reject\n\n# > 大麦\n^https?:\\/\\/acs\\.m\\.taobao\\.com\\/gw\\/mtop\\.damai\\.wireless\\.home\\.welcome\\/ - reject\n\n# > 当贝家\n^https?:\\/\\/esdk\\.tymcdn\\.com\\/dbGold\\/m\\/v2\\/mobileLiveReveal\\.do\\? - reject\n\n# > 大智慧\n^https?:\\/\\/ssp\\.dzh\\.com\\.cn\\/v2api\\/adgroupjson - reject\n\n# > 凤凰网\n^https?:\\/\\/api.newad.ifeng.com\\/ClientAdversApi1508\\?adids= - reject\n^https?:\\/\\/c1.ifengimg.com\\/.+_w1080_h1410.jpg - reject\n^https?:\\/\\/exp.3g.ifeng.com\\/coverAdversApi\\?gv=. - reject\n^https?:\\/\\/ifengad.3g.ifeng.com\\/ad\\/pv.php\\?stat= - reject\n^https?:\\/\\/iis1.deliver.ifeng.com\\/getmcode\\?adid= - reject\n\n# > 盖得排行\n^https?:\\/\\/zone\\.guiderank-app\\.com\\/guiderank-web\\/app\\/ad\\/listLaunchADByCity\\.do - reject\n\n# > 海底捞\n^https?:\\/\\/superapp\\.kiwa-tech\\.com\\/app\\/ads\\/selectList - reject\n\n# > 极简汇率\n^https?:\\/\\/explorer\\.tratao\\.com\\/api\\/client\\/v4\\/xtransfer\\/ad\\/ - reject\n\n# > 交管12123\n^https?:\\/\\/gab\\.122\\.gov\\.cn\\/eapp\\/m\\/sysquery - reject\n\n# > 京东\n^https?:\\/\\/api\\.m\\.jd.com\\/client\\.action\\?functionId=(start|queryMaterialAdverts) - reject\n^https?:\\/\\/.+\\/client?functionId=lauch\\/lauchConfig&appName=paidaojia - reject\n^https?:\\/\\/bdsp-x.jd.com\\/adx\\/ - reject\n^https?:\\/\\/m.360buyimg.com\\/mobilecms\\/s640x1136_jfs\\/ - reject\n^https?:\\/\\/ms.jr.jd.com\\/gw\\/generic\\/base\\/na\\/m\\/adInfo - reject\n^https?:\\/\\/ms\\.jr\\.jd\\.com\\/gw\\/generic\\/aladdin\\/(new)?na\\/m\\/getLoadingPicture - reject\n^https?:\\/\\/img12.360buyimg.com.+width=\\d{4}&height=\\d{4} - reject\n\n# > 库迪咖啡\n^https?:\\/\\/gateway\\.abite\\.com\\/cotti-capi\\/customer\\/position\\/list\\?code=cotti-launch-window - reject\n^https?:\\/\\/gateway\\.cotticoffee\\.com\\/cotti-capi\\/customer\\/position\\/list\\?code=cotti-launch-window - reject\n\n# > 麦当劳\n^https?:\\/\\/api\\.mcd\\.cn\\/bff\\/portal\\/(home\\/splash|richpop) - reject\n\n# > 淘宝\n^https?:\\/\\/gw.alicdn.com\\/tfs\\/.+-1125-1602 - reject\n\n# > 淘票票\n^https?:\\/\\/acs\\.m\\.taobao\\.com\\/gw\\/mtop\\.film\\.mtopadvertiseapi\\.queryadvertise\\/ - reject\n^https?:\\/\\/acs\\.m\\.taobao\\.com\\/gw\\/mtop\\.film\\.mtopadvertiseapi\\.queryloadingbanner\\/ url reject\n\n# > Papago\n^https?:\\/\\/nam\\.veta\\.naver\\.com\\/gfp\\/v1\\?u\\=ios_papago_top - reject\n\n# > 人民日报\n^https?:\\/\\/pdapis\\.pdnews\\.cn\\/api\\/rmrb-bff-display-zh\\/display\\/zh\\/c\\/launchPage\\? - reject\n\n# > 豆瓣\n^https?:\\/\\/(\\d{1,3}.){1,3}\\d{1,3}\\/view\\/dale-online\\/dale_ad\\/ - reject\n^https?:\\/\\/api.douban.com\\/v2\\/app_ads\\/common_ads - reject\n^https?:\\/\\/frodo.douban.com\\/api\\/v2\\/movie\\/banner - reject\n^https?:\\/\\/img\\d.doubanio.com\\/view\\/dale-online\\/dale_ad\\/ - reject\n\n# > 斗鱼\n^https?:\\/\\/capi.douyucdn.cn\\/lapi\\/sign\\/app(api)?\\/getinfo\\?client_sys=ios - reject\n^https?:\\/\\/capi.douyucdn.cn\\/api\\/ios_app\\/check_update - reject\n^https?:\\/\\/capi.douyucdn.cn\\/api\\/v1\\/getStartSend?client_sys=ios - reject\n^https?:\\/\\/douyucdn.cn\\/.+\\/appapi\\/getinfo - reject\n^https?:\\/\\/rtbapi.douyucdn.cn\\/japi\\/sign\\/app\\/getinfo - reject\n^https?:\\/\\/staticlive.douyucdn.cn\\/.+\\/getStartSend - reject\n^https?:\\/\\/staticlive.douyucdn.cn\\/upload\\/signs\\/ - reject\n\n# > 饿了么\n^https?:\\/\\/elemecdn.com\\/.+\\/sitemap - reject\n^https?:\\/\\/fuss10.elemecdn.com\\/.+\\/w\\/640\\/h\\/\\d{3,4} - reject\n^https?:\\/\\/fuss10.elemecdn.com\\/.+\\/w\\/750\\/h\\/\\d{3,4} - reject\n^https?:\\/\\/fuss10.elemecdn.com\\/.+.mp4 - reject\n^https?:\\/\\/m.elecfans.com\\/static\\/js\\/ad.js - reject\n^https?:\\/\\/www1.elecfans.com\\/www\\/delivery\\/ - reject\n\n# > 头条\n^https?:\\/\\/p\\d.pstatp.com\\/origin - reject\n^https?:\\/\\/pb\\d.pstatp.com\\/origin - reject\n\n# > 咸鱼\n^https?:\\/\\/gw.alicdn.com\\/mt\\/ - reject\n^https?:\\/\\/gw.alicdn.com\\/tfs\\/.+\\d{3,4}-\\d{4} - reject\n^https?:\\/\\/gw.alicdn.com\\/tps\\/.+\\d{3,4}-\\d{4} - reject\n\n# > 喜马拉雅\n^https?:\\/\\/adse.+.com\\/[a-z]{4}\\/loading\\?appid= - reject\n^https?:\\/\\/adse.ximalaya.com\\/ting\\/feed\\?appid= - reject\n^https?:\\/\\/adse.ximalaya.com\\/ting\\/loading\\?appid= - reject\n^https?:\\/\\/adse.ximalaya.com\\/ting\\?appid= - reject\n^https?:\\/\\/fdfs.xmcdn.com\\/group21\\/M03\\/E7\\/3F\\/ - reject\n^https?:\\/\\/fdfs.xmcdn.com\\/group21\\/M0A\\/95\\/3B\\/ - reject\n^https?:\\/\\/fdfs.xmcdn.com\\/group22\\/M00\\/92\\/FF\\/ - reject\n^https?:\\/\\/fdfs.xmcdn.com\\/group22\\/M05\\/66\\/67\\/ - reject\n^https?:\\/\\/fdfs.xmcdn.com\\/group22\\/M07\\/76\\/54\\/ - reject\n^https?:\\/\\/fdfs.xmcdn.com\\/group23\\/M01\\/63\\/F1\\/ - reject\n^https?:\\/\\/fdfs.xmcdn.com\\/group23\\/M04\\/E5\\/F6\\/ - reject\n^https?:\\/\\/fdfs.xmcdn.com\\/group23\\/M07\\/81\\/F6\\/ - reject\n^https?:\\/\\/fdfs.xmcdn.com\\/group23\\/M0A\\/75\\/AA\\/ - reject\n^https?:\\/\\/fdfs.xmcdn.com\\/group24\\/M03\\/E6\\/09\\/ - reject\n^https?:\\/\\/fdfs.xmcdn.com\\/group24\\/M07\\/C4\\/3D\\/ - reject\n^https?:\\/\\/fdfs.xmcdn.com\\/group25\\/M05\\/92\\/D1\\/ - reject\n\n# > 小爱音箱\n^https:\\/\\/info\\.mina\\.xiaoaisound\\.com\\/advertise\\/ - reject\n\n# > 掌阅\n^https?:\\/\\/book.img.ireader.com\\/group6\\/M00 - reject\n\n# > 易车\n^https?:\\/\\/api.ycapp.yiche.com\\/appnews\\/getadlist - reject\n^https?:\\/\\/api.ycapp.yiche.com\\/yicheapp\\/getadlist - reject\n^https?:\\/\\/api.ycapp.yiche.com\\/yicheapp\\/getappads\\/ - reject\n^https?:\\/\\/cheyouapi.ycapp.yiche.com\\/appforum\\/getusermessagecount - reject\n\n# > Youtube++\n^https?:\\/\\/api.catch.gift\\/api\\/v3\\/pagead\\/ - reject\n\n# > 网喵\n^https?:\\/\\/.+0013.+\\/upload\\/activity\\/app_flash_screen_ - reject\n\n# > 天山直播\nhttp?:\\/\\/www.tsytv.com.cn\\/api\\/app\\/ios\\/ads - reject\n\n# > 肯德基\n^https?:\\/\\/res.kfc.com.cn\\/advertisement\\/ - reject\n\n# > 首约汽车\n^https?:\\/\\/img.yun.01zhuanche.com\\/statics\\/app\\/advertisement\\/.+-750-1334 - reject\n\n# > 神舟汽车\n^https?:\\/\\/img01.10101111cdn.com\\/adpos\\/share\\/ - reject\n\n# > 流量银行\n^https?:\\/\\/bank.wo.cn\\/v9\\/getstartpage - reject\n\n# > 海盐\n^https?:\\/\\/img.ihytv.com\\/material\\/adv\\/img\\/ - reject\n\n# > 美团\n^https?:\\/\\/img.meituan.net\\/midas\\/ - reject\n^https?:\\/\\/p\\d.meituan.net\\/(mmc|wmbanner)\\/ - reject\n\n# > QQ Pim\n^https?:\\/\\/mmgr.gtimg.com\\/gjsmall\\/qqpim\\/public\\/ios\\/splash\\/.+\\/\\d{4}_\\d{4} - reject\n\n# > 界面新闻\n^https?:\\/\\/img.jiemian.com\\/ads\\/ - reject\n\n# > 汽车之家\n^https?:\\/\\/img2\\.autoimg\\.cn\\/admdfs\\/ - reject\n\n# > 起点读书\n^https?:\\/\\/mage.if.qidian.com\\/Atom.axd\\/Api\\/Client\\/GetConfIOS - reject\n\n# > 当当\n^https?:\\/\\/img\\d{2}.ddimg.cn\\/upload_img\\/.+\\/670x900 - reject\n^https?:\\/\\/img\\d{2}.ddimg.cn\\/upload_img\\/.+\\/750x1064 - reject\n^https?:\\/\\/mapi.dangdang.com\\/index.php\\?action=init&user_client=iphone - reject\n\n# > 国泰君安证券\n^https?:\\/\\/dl.app.gtja.com\\/dzswem\\/kvController\\/ - reject\n^https?:\\/\\/dl.app.gtja.com\\/operation\\/config\\/startupConfig.json - reject\n\n# > 来疯直播\n^https?:\\/\\/api.laifeng.com\\/v1\\/start\\/ads - reject\n\n# > 抖音\n^https?:\\/\\/.+.pstatp.com\\/img\\/ad - reject\n^https?:\\/\\/.+.snssdk.com\\/api\\/ad\\/ - reject\n^https?:\\/\\/aweme.snssdk.com\\/aweme\\/v1\\/aweme\\/stats\\/ - reject\n^https?:\\/\\/aweme.snssdk.com\\/aweme\\/v1\\/device\\/update\\/ - reject\n^https?:\\/\\/aweme.snssdk.com\\/aweme\\/v1\\/screen\\/ad\\/ - reject\n^https?:\\/\\/aweme.snssdk.com\\/service\\/1\\/app_logout\\/ - reject\n^https?:\\/\\/aweme.snssdk.com\\/service\\/2\\/app_log - reject\n^https?:\\/\\/frontier.snssdk.com\\/ - reject\n^https?:\\/\\/sf\\w-ttcdn-tos.pstatp.com\\/obj\\/web.business.image - reject\n\n# > 下厨房\n^https?:\\/\\/api.xiachufang.com\\/v2\\/ad\\/ - reject\n\n# > Facebook\n^https?:\\/\\/connect.facebook.net\\/en_US\\/fbadnw.js - reject\n\n# > 快递100\n^https?:\\/\\/qzonestyle.gtimg.cn\\/qzone\\/biz\\/gdt\\/mob\\/sdk\\/ios\\/v2\\/ - reject\n^https?:\\/\\/cdn.kuaidi100.com\\/images\\/open\\/appads - reject\n^https?:\\/\\/p.kuaidi100.com\\/mobile\\/mainapi.do - reject\n\n# > Mi\n^https?:\\/\\/api.m.mi.com\\/.+\\/app\\/start - reject\n^https?:\\/\\/api-mifit.huami.com\\/discovery\\/mi\\/discovery\\/homepage_ad\\? - reject\n^https?:\\/\\/api-mifit.huami.com\\/discovery\\/mi\\/discovery\\/sleep_ad\\? - reject\n^https?:\\/\\/api-mifit.huami.com\\/discovery\\/mi\\/discovery\\/sport_ad\\? - reject\n^https?:\\/\\/api-mifit.huami.com\\/discovery\\/mi\\/discovery\\/sport_summary_ad\\? - reject\n^https?:\\/\\/api-mifit.huami.com\\/discovery\\/mi\\/discovery\\/sport_training_ad\\? - reject\n^https?:\\/\\/api-mifit.huami.com\\/discovery\\/mi\\/discovery\\/step_detail_ad\\? - reject\n^https?:\\/\\/api-mifit.huami.com\\/discovery\\/mi\\/discovery\\/training_video_ad\\? - reject\n\n# > Weico\n^https?:\\/\\/overseas.weico.cc\\/portal.php\\?a=get_coopen_ads - reject\n\n# > StarFans\n^https?:\\/\\/g.cdn.pengpengla.com\\/starfantuan\\/boot-screen-info\\/ - reject\n\n# > Discuz\n^https?:\\/\\/discuz.gtimg.cn\\/cloud\\/scripts\\/discuz_tips.js - reject\n\n# > 果盘游戏\n^https?:\\/\\/sapi.guopan.cn\\/get_buildin_ad - reject\n\n# > 驾考宝典\n^https?:\\/\\/789.kakamobi.cn\\/.+adver - reject\n^https?:\\/\\/smart.789.image.mucang.cn\\/advert - reject\n\n# > 招商银行\n^https?:\\/\\/pic1cdn.cmbchina.com\\/appinitads\\/ - reject\n\n# > Cmblife\n^https?:\\/\\/mlife.cmbchina.com\\/ClientFace(Service)?\\/getAdvertisement.json - reject\n^https?:\\/\\/mlife.cmbchina.com\\/ClientFace(Service)?\\/preCacheAdvertise.json - reject\n^https?:\\/\\/resource.cmbchina.com\\/fsp\\/File\\/ClientFacePublic\\/.+.gif - reject\n\n# > ElongClient\nhttp?:\\/\\/123.59.30.10\\/adv\\/advInfos - reject\n\n# > AiRav\n^https?:\\/\\/bbs.airav.cc\\/data\\/.+.jpg - reject\n^https?:\\/\\/image.airav.cc\\/AirADPic\\/.+.gif - reject\n^https?:\\/\\/m.airav.cc\\/images\\/Mobile_popout_cn.gif - reject\n\n# > 花生地铁\n^https?:\\/\\/cmsapi.wifi8.com\\/v1\\/emptyAd\\/info - reject\n^https?:\\/\\/cmsapi.wifi8.com\\/v2\\/adNew\\/config - reject\n^https?:\\/\\/cmsfile.wifi8.com\\/uploads\\/png\\/ - reject\n\n# > AppSo\n^https?:\\/\\/sso.ifanr.com\\/jiong\\/IOS\\/appso\\/splash\\/ - reject\n\n# > 懒人听书\n^https?:\\/\\/118.178.214.118\\/yyting\\/advertclient\\/ClientAdvertList.action - reject\n^https?:\\/\\/dapis.mting.info\\/yyting\\/advertclient\\/ClientAdvertList.action - reject\n\n# > 91Porn\n^https?:\\/\\/192.133.+.mp4$ - reject\n\n# > 熊猫直播\n^https?:\\/\\/static.api.m.panda.tv\\/index.php\\?method=clientconf.firstscreen&__version=(play_cnmb|(\\d+.){0,3}\\d+)&__plat=ios&__channel=appstore - reject\n\n# > 微吼\n^https?:\\/\\/api.app.vhall.com\\/v5\\/000\\/webinar\\/launch - reject\n\n# > 天天狼人杀\n^https?:\\/\\/img.53site.com\\/Werewolf\\/AD\\/ - reject\n^https?:\\/\\/werewolf.53site.com\\/Werewolf\\/.+\\/getAdvertise.php - reject\n^https?:\\/\\/werewolf.53site.com\\/Werewolf\\/.+\\/getShareVideodb.php - reject\n\n# > Apple\n^https?:\\/\\/a.applovin.com\\/.+\\/ad - reject\n\n# > 微医\n^https?:\\/\\/app.wy.guahao.com\\/json\\/white\\/dayquestion\\/getpopad - reject\n^https?:\\/\\/kano.guahao.cn\\/.+\\?resize=\\d{3}-\\d{4} - reject\n\n# > 车来了\n^https?:\\/\\/api.chelaile.net.cn\\/adpub\\/ - reject\n^https?:\\/\\/api.chelaile.net.cn\\/goocity\\/advert\\/ - reject\n^https?:\\/\\/atrace.chelaile.net.cn\\/adpub\\/ - reject\n^https?:\\/\\/atrace.chelaile.net.cn\\/exhibit\\?&adv_image - reject\n^https?:\\/\\/pic1.chelaile.net.cn\\/adv\\/ - reject\n\n# > 健康160\n^https?:\\/\\/images.91160.com\\/primary\\/ - reject\n\n# > 1钱包\n^https?:\\/\\/d.1qianbao.com\\/youqian\\/ads\\/ - reject\n\n# > 火猫直播\n^https?:\\/\\/api.huomao.com\\/channels\\/loginAd - reject\n\n# > 快看漫画\n^https?:\\/\\/api.kkmh.com\\/v\\d\\/(ad|advertisement)\\/ - reject\n\n# > 虎扑\n^https?:\\/\\/i1.hoopchina.com.cn\\/blogfile\\/.+_\\d{3}x\\d{4} - reject\n\n# > 乐视TV\n^https?:\\/\\/.+\\/letv-gug\\/ - reject\n\n# > 芒果TV\n^https?:\\/\\/pcvideoyd.titan.mgtv.com\\/pb\\/ - reject\n\n# > Kecheng Gezi\n^https?:\\/\\/classbox2.kechenggezi.com\\/api\\/v1\\/sponge\\/pull\\?request_time= - reject\n\n# > 当当阅读\n^https?:\\/\\/e.dangdang.com\\/media\\/api.+\\?action=getDeviceStartPage - reject\n\n# > 什么值得买\n^https?:\\/\\/api.smzdm.com\\/v1\\/util\\/loading - reject\n^https?:\\/\\/api.smzdm.com\\/v2\\/util\\/banner - reject\n\n# > 飞常准\n^https?:\\/\\/app.veryzhun.com\\/ad\\/admob - reject\n\n# > 凤凰秀\n^https?:\\/\\/api.fengshows.com\\/api\\/launchAD - reject\n\n# > 人人视频\n^https?:\\/\\/img.rr.tv\\/banner\\/.+.jpg - reject\n\n# > 人人影视\n^https?:\\/\\/ctrl.(playcvn|zmzapi).net\\/app\\/(ads|init) - reject\n\n# > 老司机\n^https?:\\/\\/api.laosiji.com\\/user\\/startpage\\/ - reject\n\n# > 同花顺 Pro\n^https?:\\/\\/adm.10jqka.com.cn\\/interface\\/getads.php - reject\n\n# > 航旅纵横\n^https?:\\/\\/(discardrp|startup)\\.umetrip\\.com\\/gateway\\/api\\/umetrip\\/native - reject\n\n# > 杭州市民卡\n^https?:\\/\\/smkmp.96225.com\\/smkcenter\\/ad\\/.+\\/adBanner - reject\n\n# > 杭州公交\n^https?:\\/\\/m.ibuscloud.com\\/v2\\/app\\/getStartPage - reject\n\n# > 埋堆堆\n^https?:\\/\\/api.mddcloud.com.cn\\/api\\/ad\\/getClassAd.action - reject\n^https?:\\/\\/api.mddcloud.com.cn\\/api\\/advert\\/getHomepage.action - reject\n\n# > 叨鱼\n^https?:\\/\\/daoyu.sdo.com\\/api\\/userCommon\\/getAppStartAd - reject\n\n# > Keep\n^https?:\\/\\/api.gotokeep.com\\/ads - reject\n^https?:\\/\\/static1.keepcdn.com\\/.+\\d{3}x\\d{4} - reject\n\n# > iSafePlay\n^https?:\\/\\/aarkissltrial.secure2.footprint.net\\/v1\\/ads - reject\n^https?:\\/\\/rm.aarki.net\\/v1\\/ads - reject\n\n# > 超级课程表\n^https?:\\/\\/182.92.244.70\\/d\\/json\\/ - reject\n\n# > 飞猪\n^https?:\\/\\/acs.m.taobao.com\\/gw\\/mtop.trip.activity.querytmsresources\\/1.0\\?type=originaljson - reject\n\n# > Finger Driver\n^https?:\\/\\/.+\\/videos\\/KnifeHit_4\\/gear3\\/ - reject\n\n# > 驾图\n^https?:\\/\\/images.kartor.cn\\/.+.html - reject\n\n# > 动卡空间\n^https?:\\/\\/m.creditcard.ecitic.com\\/citiccard\\/mbk\\/.+.\\/appStartAdv - reject\n\n# > 好奇心日报\n^https?:\\/\\/app3.qdaily.com\\/app3\\/boot_advertisements.json - reject\n\n# > 分期乐\n^https?:\\/\\/fm.fenqile.com\\/routev2\\/other\\/getfloatAd.json - reject\n^https?:\\/\\/fm.fenqile.com\\/routev2\\/other\\/startImg.json - reject\n\n# > Vip mobile\n^https?:\\/\\/.+\\/vips-mobile\\/router.do\\?api_key= - reject\n\n# > 顺丰蜂巢\n^https?:\\/\\/consumer.fcbox.com\\/v1\\/ad\\/OpeningAdInfo\\/ - reject\n\n# > 威锋\n^https?:\\/\\/api.feng.com[\\s\\S]*?Claunch_screen - reject\n^https?:\\/\\/fengplus.feng.com\\/index.php\\?r=api\\/slide\\/.+Ads - reject\n\n# > 咪咕\n^https?:\\/\\/.+\\/img\\/ad.union.api\\/ - reject\n^https?:\\/\\/.+\\/v1\\/iflyad\\/ - reject\n^https?:\\/\\/ggic.cmvideo.cn\\/ad\\/ - reject\n^https?:\\/\\/ggic2.cmvideo.cn\\/ad\\/ - reject\n^https?:\\/\\/ggv.cmvideo.cn\\/v1\\/iflyad\\/ - reject\n\n# > 太平洋电脑网\n^https?:\\/\\/agent-count.pconline.com.cn\\/counter\\/adAnalyse\\/ - reject\n^https?:\\/\\/ivy.pchouse.com.cn\\/adpuba\\/ - reject\n\n# > 开源中国\n^https?:\\/\\/www.oschina.net\\/action\\/apiv2\\/get_launcher - reject\n\n# > ofo\n^https?:\\/\\/activity2.api.ofo.com\\/ofo\\/Api\\/v2\\/ads - reject\n^https?:\\/\\/ma.ofo.com\\/ads - reject\n^https?:\\/\\/supportda.ofo.com\\/adaction\\? - reject\n\n# > 四季线上影视\n^https?:\\/\\/service.4gtv.tv\\/4gtv\\/Data\\/ADLog - reject\n^https?:\\/\\/service.4gtv.tv\\/4gtv\\/Data\\/GetAD - reject\n\n# > 爱回收\n^https?:\\/\\/gw.aihuishou.com\\/app-portal\\/home\\/getadvertisement - reject\n\n# > 58同城\n^https?:\\/\\/.+\\.58cdn\\.com\\.cn\\/brandads\\/ - reject\n^https?:\\/\\/app\\.58\\.com\\/api\\/home\\/advertising\\/ - reject\n^https?:\\/\\/app\\.58\\.com\\/api\\/home\\/appadv\\/ - reject\n^https?:\\/\\/app\\.58\\.com\\/api\\/home\\/invite\\/popupAdv - reject\n^https?:\\/\\/app\\.58\\.com\\/api\\/log\\/ - reject\n\n# > 多看\n^https?:\\/\\/www.duokan.com\\/pictures? - reject\n^https?:\\/\\/www.duokan.com\\/promotion_day - reject\n\n# > 漫画人\n^https?:\\/\\/mangaapi.manhuaren.com\\/v1\\/public\\/getStartPageAds - reject\n\n# > 秒拍\n^https?:\\/\\/b-api.ins.miaopai.com\\/1\\/ad\\/ - reject\n\n# > 迅雷\n^https?:\\/\\/images.client.vip.xunlei.com\\/.+\\/advert\\/ - reject\n\n# > 天气通\n^https?:\\/\\/tqt.weibo.cn\\/.+advert.index - reject\n^https?:\\/\\/tqt.weibo.cn\\/overall\\/redirect.php\\?r=tqt_sdkad - reject\n^https?:\\/\\/tqt.weibo.cn\\/overall\\/redirect.php\\?r=tqtad - reject\n\n# > 运动世界\n^https?:\\/\\/.+.iydsj.com\\/api\\/.+\\/ad - reject\n\n# > 雅思\n^https?:\\/\\/cdn.tiku.zhan.com\\/banner - reject\n\n# > 美味不用等\n^https?:\\/\\/capi.mwee.cn\\/app-api\\/V12\\/app\\/getstartad - reject\n\n# > AcFun\n^https?:\\/\\/aes.acfun.cn\\/s\\?adzones - reject\n\n# > 讯飞\n^https?:\\/\\/imeclient.openspeech.cn\\/adservice\\/ - reject\n\n# > Yahoo\n^https?:\\/\\/m.yap.yahoo.com\\/v18\\/getAds.do - reject\n\n# > 抱抱\n^https?:\\/\\/www.myhug.cn\\/ad\\/ - reject\n\n# > 麻花影视\n^https?:\\/\\/.+\\/api\\/app\\/member\\/ver2\\/user\\/login\\/ - reject\n\n# > 直播吧\n^https?:\\/\\/a.qiumibao.com\\/activities\\/config.php - reject\n^https?:\\/\\/.+\\/allOne.php\\?ad_name - reject\n\n# > 穷游\n^https?:\\/\\/open.qyer.com\\/qyer\\/startpage\\/ - reject\n^https?:\\/\\/open.qyer.com\\/qyer\\/config\\/get - reject\n^https?:\\/\\/media.qyer.com\\/ad\\/ - reject\n\n# > 肆客足球\n^https?:\\/\\/api.qiuduoduo.cn\\/guideimage - reject\n\n# > 萤石云视频\n^https?:\\/\\/i.ys7.com\\/api\\/ads - reject\n\n# > 电视家\n^https?:\\/\\/api.gaoqingdianshi.com\\/api\\/v2\\/ad - reject\n\n# > 虎扑\n^https?:\\/\\/i\\d.hoopchina.com.cn\\/blogfile\\/\\/d+\\/\\/d+\\/BbsImg.(?<=(big.(png|jpg)))$ - reject\n^https?:\\/\\/games.mobileapi.hupu.com\\/.+\\/(search|interfaceAdMonitor|status|hupuBbsPm)\\/(hotkey|init|hupuBbsPm). - reject\n^https?:\\/\\/games.mobileapi.hupu.com\\/interfaceAdMonitor - reject\n\n# > 高德\n^https?:\\/\\/amap-aos-info-nogw\\.amap\\.com\\/ws\\/aos\\/alimama\\/ - reject\n^https?:\\/\\/m\\d\\.amap\\.com\\/ws\\/faas\\/amap-navigation\\/main-page-(assets|location)\\? - reject\n^https?:\\/\\/m\\d\\.amap\\.com\\/ws\\/mapapi\\/hint_text\\/offline_data\\? - reject\n^https?:\\/\\/m\\d\\.amap\\.com\\/ws\\/message\\/notice\\/list\\? - reject\n^https?:\\/\\/m\\d\\.amap\\.com\\/ws\\/shield\\/(scene/recommend|search/new_hotword)\\? - reject\n^https?:\\/\\/m\\d\\.amap\\.com\\/ws\\/valueadded\\/alimama\\/splash_screen\\? - reject\n^https?:\\/\\/optimus-ads\\.amap\\.com\\/uploadimg\\/[a-zA-Z0-9]+\\.gif - reject\n^https?:\\/\\/render-oss-cdn\\.amap\\.com\\/render\\/studio-dev\\/image\\/ - reject\n^https?:\\/\\/sns\\.amap\\.com\\/ws\\/msgbox\\/pull_mp\\? - reject\n\n# > 虾米音乐\n^https?:\\/\\/pic.xiami.net\\/images\\/common\\/uploadpic[\\s\\S]*?.jpg$ - reject\n\n# > 作业帮\n^https?:\\/\\/img.zuoyebang.cc\\/zyb-image[\\s\\S]*?.jpg - reject\n\n# > bilibili\n^https?:\\/\\/api.bilibili.com\\/pgc\\/season\\/rank\\/cn - reject\n^https?:\\/\\/app.bilibili.com\\/x\\/v2\\/rank.*rid=168 - reject\n^https?:\\/\\/app.bilibili.com\\/x\\/v2\\/rank.*rid=5 - reject\n^https?:\\/\\/app.bilibili.com\\/x\\/v2\\/search\\/defaultword - reject\n^https?:\\/\\/app.bilibili.com\\/x\\/v2\\/search\\/hot - reject\n^https?:\\/\\/app.bilibili.com\\/x\\/v2\\/search\\/recommend - reject\n\n# > 一点万象\n^https?:\\/\\/app.mixcapp.com\\/mixc\\/api\\/v2\\/ad - reject\n\n# > 一号会员店\n^https?:\\/\\/api\\.m\\.jd.com\\/client\\.action\\?functionId=home_launchConfig - reject\n^https?:\\/\\/venus\\.yhd\\.com\\/memhome\\/launchConfig - reject\n\n# > WiFi共享大师\n^https?:\\/\\/nochange.ggsafe.com\\/ad\\/ - reject\n\n# > 蜗牛睡眠\n^https?:\\/\\/snailsleep.net\\/snail\\/v1\\/adTask\\/ - reject\n^https?:\\/\\/snailsleep.net\\/snail\\/v1\\/screen\\/qn\\/get\\? - reject\n\n# > 小红书\n^https?:\\/\\/ads-img-al\\.xhscdn\\.com\\/hera\\/ - reject\n^https?:\\/\\/edith\\.xiaohongshu\\.com\\/api\\/sns\\/v\\d\\/system_service\\/config\\? - reject\n^https?:\\/\\/edith\\.xiaohongshu\\.com\\/api\\/sns\\/v\\d\\/system_service\\/splash_config$ - reject\n^https?:\\/\\/www\\.xiaohongshu\\.com\\/api\\/sns\\/v\\d\\/(tag\\/)?ads - reject\n\n# > 小睡眠\n^https?:\\/\\/api.psy-1.com\\/cosleep\\/startup - reject\n\n# > Yahoo!\n^https?:\\/\\/m.yap.yahoo.com\\/v18\\/getAds.do - reject\n\n# > WeDoctor\n^https?:\\/\\/app.wy.guahao.com\\/json\\/white\\/dayquestion\\/getpopad - reject\n\n# > Zepp Life\n^https?://api-mifit-cn2\\.zepp\\.com/discovery/mi/cards/(startpage_ad|homepage_ad)\\? - reject\n\n# > 掌上生活\n^https?:\\/\\/mbasecc\\.bas\\.cmbchina\\.com\\/Edge\\/api\\/mlife\\.clientface\\.clientservice\\.api\\.advertiseService\\/preCacheAdvertiseSec - reject\n\n# > 字节跳动联盟\n^https?:\\/\\/api-access\\.pangolin-sdk-toutiao1?\\.com\\/api\\/ad\\/ - reject\n\n# > 无他\n^https?:\\/\\/api-release.wuta-cam.com\\/ad_tree - reject\n^https?:\\/\\/res-release.wuta-cam.com\\/json\\/ads_component_cache.json - reject\n\n# > 向日葵\n^https?:\\/\\/slapi.oray.net\\/client\\/ad - reject\n\n# > 雪球\n^https?:\\/\\/api\\.xueqiu\\.com\\/snowpard\\/launch_strategy\\/query\\.json - reject\n\n# > 识货\n^https?:\\/\\/www.shihuo.cn\\/app3\\/saveAppInfo - reject\n\n# > AbemaTV Unlock\n^https?:\\/\\/api.abema.io\\/v\\d\\/ip\\/check - reject\n\n# > Other\n^https?:\\/\\/.+allOne.php\\?ad_name=main_splash_ios - reject\n^https?:\\/\\/.+nga.cn.+\\bhome.+\\b=ad - reject\n^https?:\\/\\/.+resource=article\\/recommend\\&accessToken= - reject\n^https?:\\/\\/113.200.76.*:16420\\/sxtd.bike2.01\\/getkey.do - reject\n^https?:\\/\\/cdn.api.fotoable.com\\/Advertise\\/ - reject\n^https?:\\/\\/counter.ksosoft.com\\/ad.php - reject\n^https?:\\/\\/creatives.ftimg.net\\/ads - reject\n^https?:\\/\\/dd.iask.cn\\/ddd\\/adAudit - reject\n^https?:\\/\\/g.tbcdn.cn\\/mtb\\/ - reject\n^https?:\\/\\/huichuan.sm.cn\\/jsad - reject\n^https?:\\/\\/iflow.uczzd.cn\\/log\\/ - reject\n^https?:\\/\\/iphone265g.com\\/templates\\/iphone\\/bottomAd.js - reject\n^https?:\\/\\/m.+.china.com.cn\\/statics\\/sdmobile\\/js\\/ad - reject\n^https?:\\/\\/m.+.china.com.cn\\/statics\\/sdmobile\\/js\\/mobile.advert.js - reject\n^https?:\\/\\/m.+.china.com.cn\\/statics\\/sdmobile\\/js\\/mobileshare.js - reject\n^https?:\\/\\/m.elecfans.com\\/static\\/js\\/ad.js - reject\n^https?:\\/\\/mobile-pic.cache.iciba.com\\/feeds_ad\\/ - reject\n^https?:\\/\\/nga.cn.+\\bhome.+\\b=ad - reject\n^https?:\\/\\/overseas.weico.cc\\/portal.php\\?a=get_coopen_ads - reject\n^https?:\\/\\/player.hoge.cn\\/advertisement.swf - reject\n^https?:\\/\\/ress.dxpmedia.com\\/appicast\\/ - reject\n^https?:\\/\\/s3.pstatp.com\\/inapp\\/TTAdblock.css - reject\n^https?:\\/\\/sdk.99shiji.com\\/ad\\/ - reject\n^https?:\\/\\/statc.mytuner.mobi\\/media\\/banners\\/ - reject\n^https?:\\/\\/static.cnbetacdn.com\\/assets\\/adv - reject\n^https?:\\/\\/static.iask.cn\\/m-v20161228\\/js\\/common\\/adAudit.min.js - reject\n^https?:\\/\\/v.17173.com\\/api\\/Allyes\\/ - reject\n^https?:\\/\\/wmedia-track.uc.cn - reject\n^https?:\\/\\/www.ft.com\\/__origami\\/service\\/image\\/v2\\/images\\/raw\\/https%3A%2F%2Fcreatives.ftimg.net%2Fads* - reject\n^https?:\\/\\/www.lianbijr.com\\/adPage\\/ - reject\n\n[Script]\n# > Bilibili\nhttp-response ^https?://app\\.bilibili\\.com/x/v\\d/splash/list script-path=https://cdn.jsdelivr.net/gh/srk24/profile@master/js/bilibili_splash.js\n\n# > TestFlight\nhttp-request ^https?:\\/\\/testflight\\.apple\\.com\\/v\\d\\/accounts\\/.+?\\/install$ requires-body=1,max-size=0,script-path=https://gist.githubusercontent.com/NobyDa/9be418b93afc5e9c8a8f4d28ae403cf2/raw/TF_Download.js\n\n[MITM]\nskip-server-cert-verify = true\n\nhostname = *.chelaile.net.cn,*.cnbetacdn.com,*.didistatic.com,*.google.cn,*.google-analytics.com,*.iydsj.com,*.k.sohu.com,*.kfc.com,*.kingsoft-office-service.com,*.meituan.net,*.ofo.com,*.pixiv.net,*.wikipedia.org,*.wikiwand.com,*.ydstatic.com,*.youdao.com,*.zhuishushenqi.com,*.zymk.cn,101.201.62.22,113.105.222.132,113.96.109.*,118.178.214.118,119.18.193.135,121.14.89.216,121.9.212.178,123.59.31.1,14.21.76.30,153.3.236.81,180.101.212.22,183.232.237.194,183.232.246.225,183.60.159.227,218.11.3.70,59.151.53.6,59.37.96.220,789.kakamobi.cn,a.apicloud.com,a.applovin.com,a.qiumibao.com,a.sfansclub.com,a.wkanx.com,aarkissltrial.secure2.footprint.net,acs.m.taobao.com,act.vip.iqiyi.com,activity2.api.ofo.com,adm.10jqka.com.cn,ads-img-al.xhscdn.com,adse.ximalaya.com,afd.baidu.com,amap-aos-info-nogw.amap.com,api*.musical.ly,api.abema.io,api.app.vhall.com,api.bilibili.com,api.chelaile.net.cn,api.daydaycook.com.cn,api.feng.com,api.fengshows.com,api.gotokeep.com,api.huomao.com,api.intsig.net,api.jxedt.com,api.k.sohu.com,api.kkmh.com,api.laifeng.com,api.m.jd.com,api.mcd.cn,api.mddcloud.com.cn,api.mgzf.com,api.psy-1.com,api.rr.tv,api.smzdm.com,api.tv.sohu.com,api.wallstreetcn.com,api.xiachufang.com,api.xueqiu.com,api.zhuishushenqi.com,api5.futunn.com,api-access.pangolin-sdk-toutiao.com,api-access.pangolin-sdk-toutiao1.com,api-mifit.huami.com,api-mifit-cn.huami.com,api-mifit-cn2.zepp.com,api-release.wuta-cam.com,app.10086.cn,app.58.com,app.api.ke.com ,app.biliintl.com,app.m.zj.chinamobile.com,app.mixcapp.com,app.variflight.com,app.wy.guahao.com,api3.cls.cn,appsdk.soku.com,atrace.chelaile.net.cn,b.zhuishushenqi.com,c.m.163.com,cap.caocaokeji.cn,capi.douyucdn.cn,capi.mwee.cn,cdn.fivecdm.com,cdn.kuaidi100.com,cdn.moji.com,channel.beitaichufang.com,classbox2.kechenggezi.com,client.mail.163.com,cms.daydaycook.com.cn,cn-acs.m.cainiao.com,connect.facebook.net,creatives.ftimg.net,creditcard.ecitic.com,d.1qianbao.com,daoyu.sdo.com,dapis.mting.info,dl.app.gtja.com,dongfeng.alicdn.com,discardrp.umetrip.com,dsp-impr2.youdao.com,dspsdk.abreader.com,e.dangdang.com,edith.xiaohongshu.com,esdk.tymcdn.com,explorer.tratao.com,fdfs.xmcdn.com,fm.fenqile.com,fuss10.elemecdn.com,g1.163.com,gab.122.gov.cn,gateway.abite.com,gateway.cotticoffee.com,gateway.shouqiev.com,shopapi.io.mi.com,gorgon.youdao.com,gw.alicdn.com,gw-passenger.01zhuanche.com,home.mi.com,hm.xiaomi.com,hui.sohu.com,huichuan.sm.cn,i.weread.qq.com,i.ys7.com,i1.hoopchina.com.cn,iapi.bishijie.com,iface.iqiyi.com,iface2.iqiyi.com,img.jiemian.com,img.zuoyebang.cc,img01.10101111cdn.com,img1.126.net,img2.autoimg.cn,impservice.dictapp.youdao.com,impservice.youdao.com,info.mina.xiaoaisound.com,interface.music.163.com,ios.wps.cn,issuecdn.baidupcs.com,kano.guahao.cn,lives.l.qq.com,m*.amap.com,m.aty.sohu.com,m.client.10010.com,m.creditcard.ecitic.com,m.ibuscloud.com,m.yap.yahoo.com,ma.ofo.com,mage.if.qidian.com,mapi.appvipshop.com,mapi.mafengwo.cn,mbasecc.bas.cmbchina.com,mbl.56.com,media.qyer.com,mi.gdt.qq.com,mimg.127.net,mmg.aty.sohu.com,mmgr.gtimg.com,mob.mddcloud.com.cn,mobile-api2011.elong.com,mp.weixin.qq.com,mrobot.pcauto.com.cn,mrobot.pconline.com.cn,ms.jr.jd.com,msspjh.emarbox.com,nam.veta.naver.com,newclient.map.baidu.com,newsso.map.qq.com,nex.163.com,nnapp.cloudbae.cn,open.qyer.com,optimus-ads.amap.com,p.kuaidi100.com,p1.music.126.net,pan.baidu.com,passport.biliintl.com,pdapis.pdnews.cn,pic.k.sohu.com,pic1.chelaile.net.cn,pic1cdn.cmbchina.com,pic2.zhimg.com,portal-xunyou.qingcdn.com,pss.txffp.com,r.inews.qq.com,render.alipay.com,render-oss-cdn.amap.com,resource.cmbchina.com,res-release.wuta-cam.com,ress.dxpmedia.com,richmanapi.jxedt.com,rm.aarki.net,rtbapi.douyucdn.cn,service.4gtv.tv,shop-api.retail.mi.com,slapi.oray.net,smkmp.96225.com,snailsleep.net,sns.amap.com,sp.kaola.com,ssl.kohsocialapp.qq.com,sso.ifanr.com,ssp.dzh.com.cn,static.api.m.panda.tv,static.vuevideo.net,static1.keepcdn.com,staticlive.douyucdn.cn,startup.umetrip.com,superapp.kiwa-tech.com,support.you.163.com,supportda.ofo.com,switch.jumpvg.com,testflight.apple.com,thor.weidian.com,ups.youku.com,venus.yhd.com,wapwenku.baidu.com,wenku.baidu.com,www.dandanzan.com,www.facebook.com,www.firefox.com.cn,www.flyertea.com,www.ft.com,www.oschina.net,www.xiaohongshu.com,zhidao.baidu.com,zone.guiderank-app.com', 'conf', '{}', '2025-08-13 00:12:37.809', '2025-08-15 22:00:50.528'); +INSERT INTO `subscribe_application` (`id`, `name`, `icon`, `description`, `scheme`, `user_agent`, `is_default`, `subscribe_template`, `output_format`, `download_link`, `created_at`, `updated_at`) VALUES (1, 'Default', '', '', '', 'default', 1, '{{- $GiB := 1073741824.0 -}}\n{{- $used := printf \"%.2f\" (divf (add (.UserInfo.Download | default 0 | float64) (.UserInfo.Upload | default 0 | float64)) $GiB) -}}\n{{- $traffic := (.UserInfo.Traffic | default 0 | float64) -}}\n{{- $total := printf \"%.2f\" (divf $traffic $GiB) -}}\n\n{{- $exp := \"\" -}}\n{{- $expStr := printf \"%v\" .UserInfo.ExpiredAt -}}\n{{- if regexMatch `^[0-9]+$` $expStr -}}\n {{- $ts := $expStr | float64 -}}\n {{- $sec := ternary (divf $ts 1000.0) $ts (ge (len $expStr) 13) -}}\n {{- $exp = (date \"2006-01-02 15:04:05\" (unixEpoch ($sec | int64))) -}}\n{{- else -}}\n {{- $exp = $expStr -}}\n{{- end -}}\n\nREMARKS={{ .SiteName }}-{{ .SubscribeName }}\nSTATUS=Traffic: {{ $used }} GiB/{{ $total }} GiB | Expires: {{ $exp }}\n\n{{- range $proxy := .Proxies }}\n {{- $server := $proxy.Server -}}\n {{- if and (contains $proxy.Server \":\") (not (hasPrefix \"[\" $proxy.Server)) -}}\n {{- $server = printf \"[%s]\" $proxy.Server -}}\n {{- end -}}\n\n {{- $sni := default \"\" $proxy.SNI -}}\n {{- if eq $sni \"\" -}}\n {{- $sni = default \"\" $proxy.Host -}}\n {{- end -}}\n {{- if and (eq $sni \"\") (not (or (regexMatch \"^[0-9]+\\\\.[0-9]+\\\\.[0-9]+\\\\.[0-9]+$\" $proxy.Server) (contains $proxy.Server \":\"))) -}}\n {{- $sni = $proxy.Server -}}\n {{- end -}}\n\n {{- $common := \"udp=1&tfo=1\" -}}\n\n {{- $password := $.UserInfo.Password -}}\n {{- if and (eq $proxy.Type \"shadowsocks\") (ne (default \"\" $proxy.ServerKey) \"\") -}}\n {{- $method := $proxy.Method -}}\n {{- if or (hasPrefix \"2022-blake3-\" $method) (eq $method \"2022-blake3-aes-128-gcm\") (eq $method \"2022-blake3-aes-256-gcm\") -}}\n {{- $userKeyLen := ternary 16 32 (hasSuffix \"128-gcm\" $method) -}}\n {{- $pwdStr := printf \"%s\" $password -}}\n {{- $userKey := ternary $pwdStr (trunc $userKeyLen $pwdStr) (le (len $pwdStr) $userKeyLen) -}}\n {{- $serverB64 := b64enc $proxy.ServerKey -}}\n {{- $userB64 := b64enc $userKey -}}\n {{- $password = printf \"%s:%s\" $serverB64 $userB64 -}}\n {{- end -}}\n {{- end -}}\n\n {{- if eq $proxy.Type \"shadowsocks\" }}\nss://{{ printf \"%s:%s\" $proxy.Method $password | b64enc }}@{{ $server }}:{{ $proxy.Port }}?{{ $common }}#{{ $proxy.Name }}\n {{- else if eq $proxy.Type \"vmess\" }}\nvmess://{{ (dict \"v\" \"2\" \"ps\" $proxy.Name \"add\" $proxy.Server \"port\" (printf \"%d\" $proxy.Port) \"id\" $password \"aid\" \"0\" \"net\" (default \"tcp\" $proxy.Transport) \"type\" \"none\" \"host\" (default \"\" $proxy.Host) \"path\" (default \"\" $proxy.Path) \"tls\" (ternary \"tls\" \"\" (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\"))) \"sni\" $sni) | toJson | b64enc }}\n {{- else if eq $proxy.Type \"vless\" }}\nvless://{{ $password }}@{{ $server }}:{{ $proxy.Port }}?encryption=none{{- if ne (default \"\" $proxy.Flow) \"\" }}&flow={{ $proxy.Flow }}{{- end }}{{- if ne $proxy.Transport \"\" }}&type={{ $proxy.Transport }}{{- end }}{{- if and (eq $proxy.Transport \"ws\") (ne (default \"\" $proxy.Host) \"\") }}&host={{ $proxy.Host }}{{- end }}{{- if and (eq $proxy.Transport \"ws\") (ne (default \"\" $proxy.Path) \"\") }}&path={{ $proxy.Path | urlquery }}{{- end }}{{- if and (eq $proxy.Transport \"grpc\") (ne (default \"\" $proxy.ServiceName) \"\") }}&serviceName={{ $proxy.ServiceName }}{{- end }}{{- if or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\") }}&security={{ $proxy.Security }}{{- end }}{{- if ne $sni \"\" }}&sni={{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}&allowInsecure=1{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}&fp={{ $proxy.Fingerprint }}{{- end }}{{- if and (eq $proxy.Security \"reality\") (ne (default \"\" $proxy.RealityPublicKey) \"\") }}&pbk={{ $proxy.RealityPublicKey }}{{- end }}{{- if and (eq $proxy.Security \"reality\") (ne (default \"\" $proxy.RealityShortId) \"\") }}&sid={{ $proxy.RealityShortId }}{{- end }}&{{ $common }}#{{ $proxy.Name }}\n {{- else if eq $proxy.Type \"trojan\" }}\ntrojan://{{ $password }}@{{ $server }}:{{ $proxy.Port }}{{- if or (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\")) (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) $proxy.AllowInsecure) (ne $proxy.Transport \"\") }}?{{- end }}{{- if and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\") }}sni={{ $sni }}{{- end }}{{- if and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) $proxy.AllowInsecure }}{{- if and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\") }}&{{- end }}allowInsecure=1{{- end }}{{- if ne $proxy.Transport \"\" }}{{- if or (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\")) (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) $proxy.AllowInsecure) }}&{{- end }}type={{ $proxy.Transport }}{{- end }}{{- if and (eq $proxy.Transport \"ws\") (ne (default \"\" $proxy.Host) \"\") }}{{- if or (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\")) (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) $proxy.AllowInsecure) (ne $proxy.Transport \"\") }}&{{- end }}host={{ $proxy.Host }}{{- end }}{{- if and (eq $proxy.Transport \"ws\") (ne (default \"\" $proxy.Path) \"\") }}{{- if or (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\")) (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) $proxy.AllowInsecure) (ne $proxy.Transport \"\") (and (eq $proxy.Transport \"ws\") (ne (default \"\" $proxy.Host) \"\")) }}&{{- end }}path={{ $proxy.Path | urlquery }}{{- end }}{{- if or (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\")) (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) $proxy.AllowInsecure) (ne $proxy.Transport \"\") }}&{{ $common }}{{- else }}?{{ $common }}{{- end }}#{{ $proxy.Name }}\n {{- else if eq $proxy.Type \"hysteria2\" }}\nhysteria2://{{ $server }}:{{ $proxy.Port }}{{- if or (ne $password \"\") (ne $sni \"\") $proxy.AllowInsecure (ne (default \"\" $proxy.ObfsPassword) \"\") (ne (default \"\" $proxy.HopPorts) \"\") }}?{{- end }}{{- if ne $password \"\" }}auth={{ $password }}{{- end }}{{- if ne $sni \"\" }}{{- if ne $password \"\" }}&{{- end }}sni={{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}{{- if or (ne $password \"\") (ne $sni \"\") }}&{{- end }}insecure=1{{- end }}{{- if ne (default \"\" $proxy.ObfsPassword) \"\" }}{{- if or (ne $password \"\") (ne $sni \"\") $proxy.AllowInsecure }}&{{- end }}obfs=salamander&obfs-password={{ $proxy.ObfsPassword }}{{- end }}{{- if ne (default \"\" $proxy.HopPorts) \"\" }}{{- if or (ne $password \"\") (ne $sni \"\") $proxy.AllowInsecure (ne (default \"\" $proxy.ObfsPassword) \"\") }}&{{- end }}mport={{ $proxy.HopPorts }}{{- end }}{{- if or (ne $password \"\") (ne $sni \"\") $proxy.AllowInsecure (ne (default \"\" $proxy.ObfsPassword) \"\") (ne (default \"\" $proxy.HopPorts) \"\") }}&{{ $common }}{{- else }}?{{ $common }}{{- end }}#{{ $proxy.Name }}\n {{- else if eq $proxy.Type \"tuic\" }}\ntuic://{{ $password }}:{{ $password }}@{{ $server }}:{{ $proxy.Port }}{{- if or (ne (default \"\" $proxy.CongestionController) \"\") (ne (default \"\" $proxy.UDPRelayMode) \"\") $proxy.ReduceRtt $proxy.DisableSNI (ne $sni \"\") $proxy.AllowInsecure }}?{{- end }}{{- if ne (default \"\" $proxy.CongestionController) \"\" }}congestion_controller={{ $proxy.CongestionController }}{{- end }}{{- if ne (default \"\" $proxy.UDPRelayMode) \"\" }}{{- if ne (default \"\" $proxy.CongestionController) \"\" }}&{{- end }}udp_relay_mode={{ $proxy.UDPRelayMode }}{{- end }}{{- if $proxy.ReduceRtt }}{{- if or (ne (default \"\" $proxy.CongestionController) \"\") (ne (default \"\" $proxy.UDPRelayMode) \"\") }}&{{- end }}reduce_rtt=1{{- end }}{{- if $proxy.DisableSNI }}{{- if or (ne (default \"\" $proxy.CongestionController) \"\") (ne (default \"\" $proxy.UDPRelayMode) \"\") $proxy.ReduceRtt }}&{{- end }}disable_sni=1{{- end }}{{- if ne $sni \"\" }}{{- if or (ne (default \"\" $proxy.CongestionController) \"\") (ne (default \"\" $proxy.UDPRelayMode) \"\") $proxy.ReduceRtt $proxy.DisableSNI }}&{{- end }}sni={{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}{{- if or (ne (default \"\" $proxy.CongestionController) \"\") (ne (default \"\" $proxy.UDPRelayMode) \"\") $proxy.ReduceRtt $proxy.DisableSNI (ne $sni \"\") }}&{{- end }}allow_insecure=1{{- end }}{{- if or (ne (default \"\" $proxy.CongestionController) \"\") (ne (default \"\" $proxy.UDPRelayMode) \"\") $proxy.ReduceRtt $proxy.DisableSNI (ne $sni \"\") $proxy.AllowInsecure }}&{{ $common }}{{- else }}?{{ $common }}{{- end }}#{{ $proxy.Name }}\n {{- else if eq $proxy.Type \"anytls\" }}\nanytls://{{ $password }}@{{ $server }}:{{ $proxy.Port }}{{- if ne $sni \"\" }}?sni={{ $sni }}&{{ $common }}{{- else }}?{{ $common }}{{- end }}#{{ $proxy.Name }}\n {{- end }}\n{{- end }}\n\n{{- range $proxy := .Proxies }}\n {{- if not (or (eq $proxy.Type \"shadowsocks\") (eq $proxy.Type \"vmess\") (eq $proxy.Type \"vless\") (eq $proxy.Type \"trojan\") (eq $proxy.Type \"hysteria2\") (eq $proxy.Type \"tuic\") (eq $proxy.Type \"anytls\")) }}\n# Skipped (unsupported protocol): {{ $proxy.Name }} ({{ $proxy.Type }})\n {{- end }}\n{{- end }}\n', 'base64', '{}', '2025-08-12 22:57:56.711', '2025-08-15 21:45:20.181'); +INSERT INTO `subscribe_application` (`id`, `name`, `icon`, `description`, `scheme`, `user_agent`, `is_default`, `subscribe_template`, `output_format`, `download_link`, `created_at`, `updated_at`) VALUES (2, 'Shadowsocket', '', '', 'shadowrocket://add/sub://${window.btoa(url)}?remark=${encodeURIComponent(name)}', 'Shadowsocket', 0, '{{- $GiB := 1073741824.0 -}}\n{{- $used := printf \"%.2f\" (divf (add (.UserInfo.Download | default 0 | float64) (.UserInfo.Upload | default 0 | float64)) $GiB) -}}\n{{- $traffic := (.UserInfo.Traffic | default 0 | float64) -}}\n{{- $total := printf \"%.2f\" (divf $traffic $GiB) -}}\n\n{{- $exp := \"\" -}}\n{{- $expStr := printf \"%v\" .UserInfo.ExpiredAt -}}\n{{- if regexMatch `^[0-9]+$` $expStr -}}\n {{- $ts := $expStr | float64 -}}\n {{- $sec := ternary (divf $ts 1000.0) $ts (ge (len $expStr) 13) -}}\n {{- $exp = (date \"2006-01-02 15:04:05\" (unixEpoch ($sec | int64))) -}}\n{{- else -}}\n {{- $exp = $expStr -}}\n{{- end -}}\n\nREMARKS={{ .SiteName }}-{{ .SubscribeName }}\nSTATUS=Traffic: {{ $used }} GiB/{{ $total }} GiB | Expires: {{ $exp }}\n\n{{- range $proxy := .Proxies }}\n {{- $server := $proxy.Server -}}\n {{- if and (contains $proxy.Server \":\") (not (hasPrefix \"[\" $proxy.Server)) -}}\n {{- $server = printf \"[%s]\" $proxy.Server -}}\n {{- end -}}\n\n {{- $sni := default \"\" $proxy.SNI -}}\n {{- if eq $sni \"\" -}}\n {{- $sni = default \"\" $proxy.Host -}}\n {{- end -}}\n {{- if and (eq $sni \"\") (not (or (regexMatch \"^[0-9]+\\\\.[0-9]+\\\\.[0-9]+\\\\.[0-9]+$\" $proxy.Server) (contains $proxy.Server \":\"))) -}}\n {{- $sni = $proxy.Server -}}\n {{- end -}}\n\n {{- $common := \"udp=1&tfo=1\" -}}\n\n {{- $password := $.UserInfo.Password -}}\n {{- if and (eq $proxy.Type \"shadowsocks\") (ne (default \"\" $proxy.ServerKey) \"\") -}}\n {{- $method := $proxy.Method -}}\n {{- if or (hasPrefix \"2022-blake3-\" $method) (eq $method \"2022-blake3-aes-128-gcm\") (eq $method \"2022-blake3-aes-256-gcm\") -}}\n {{- $userKeyLen := ternary 16 32 (hasSuffix \"128-gcm\" $method) -}}\n {{- $pwdStr := printf \"%s\" $password -}}\n {{- $userKey := ternary $pwdStr (trunc $userKeyLen $pwdStr) (le (len $pwdStr) $userKeyLen) -}}\n {{- $serverB64 := b64enc $proxy.ServerKey -}}\n {{- $userB64 := b64enc $userKey -}}\n {{- $password = printf \"%s:%s\" $serverB64 $userB64 -}}\n {{- end -}}\n {{- end -}}\n\n {{- if eq $proxy.Type \"shadowsocks\" }}\nss://{{ printf \"%s:%s\" (default \"aes-128-gcm\" $proxy.Method) $password | b64enc }}@{{ $server }}:{{ $proxy.Port }}?{{ $common }}#{{ $proxy.Name }}\n {{- else if eq $proxy.Type \"vmess\" }}\nvmess://{{ (dict \"v\" \"2\" \"ps\" $proxy.Name \"add\" $proxy.Server \"port\" (printf \"%d\" $proxy.Port) \"id\" $password \"aid\" \"0\" \"net\" (default \"tcp\" $proxy.Transport) \"type\" \"none\" \"host\" (default \"\" $proxy.Host) \"path\" (default \"\" $proxy.Path) \"tls\" (ternary \"tls\" \"\" (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\"))) \"sni\" $sni) | toJson | b64enc }}\n {{- else if eq $proxy.Type \"vless\" }}\nvless://{{ $password }}@{{ $server }}:{{ $proxy.Port }}?encryption=none{{- if ne (default \"\" $proxy.Flow) \"\" }}&flow={{ $proxy.Flow }}{{- end }}{{- if ne $proxy.Transport \"\" }}&type={{ $proxy.Transport }}{{- end }}{{- if and (eq $proxy.Transport \"ws\") (ne (default \"\" $proxy.Host) \"\") }}&host={{ $proxy.Host }}{{- end }}{{- if and (eq $proxy.Transport \"ws\") (ne (default \"\" $proxy.Path) \"\") }}&path={{ $proxy.Path | urlquery }}{{- end }}{{- if and (eq $proxy.Transport \"grpc\") (ne (default \"\" $proxy.ServiceName) \"\") }}&serviceName={{ $proxy.ServiceName }}{{- end }}{{- if or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\") }}&security={{ $proxy.Security }}{{- end }}{{- if ne $sni \"\" }}&sni={{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}&allowInsecure=1{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}&fp={{ $proxy.Fingerprint }}{{- end }}{{- if and (eq $proxy.Security \"reality\") (ne (default \"\" $proxy.RealityPublicKey) \"\") }}&pbk={{ $proxy.RealityPublicKey }}{{- end }}{{- if and (eq $proxy.Security \"reality\") (ne (default \"\" $proxy.RealityShortId) \"\") }}&sid={{ $proxy.RealityShortId }}{{- end }}&{{ $common }}#{{ $proxy.Name }}\n {{- else if eq $proxy.Type \"trojan\" }}\ntrojan://{{ $password }}@{{ $server }}:{{ $proxy.Port }}{{- if or (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\")) (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) $proxy.AllowInsecure) (ne $proxy.Transport \"\") }}?{{- end }}{{- if and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\") }}sni={{ $sni }}{{- end }}{{- if and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) $proxy.AllowInsecure }}{{- if and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\") }}&{{- end }}allowInsecure=1{{- end }}{{- if ne $proxy.Transport \"\" }}{{- if or (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\")) (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) $proxy.AllowInsecure) }}&{{- end }}type={{ $proxy.Transport }}{{- end }}{{- if and (eq $proxy.Transport \"ws\") (ne (default \"\" $proxy.Host) \"\") }}{{- if or (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\")) (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) $proxy.AllowInsecure) (ne $proxy.Transport \"\") }}&{{- end }}host={{ $proxy.Host }}{{- end }}{{- if and (eq $proxy.Transport \"ws\") (ne (default \"\" $proxy.Path) \"\") }}{{- if or (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\")) (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) $proxy.AllowInsecure) (ne $proxy.Transport \"\") (and (eq $proxy.Transport \"ws\") (ne (default \"\" $proxy.Host) \"\")) }}&{{- end }}path={{ $proxy.Path | urlquery }}{{- end }}{{- if or (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\")) (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) $proxy.AllowInsecure) (ne $proxy.Transport \"\") }}&{{ $common }}{{- else }}?{{ $common }}{{- end }}#{{ $proxy.Name }}\n {{- else if eq $proxy.Type \"hysteria2\" }}\nhysteria2://{{ $server }}:{{ $proxy.Port }}{{- if or (ne $password \"\") (ne $sni \"\") $proxy.AllowInsecure (ne (default \"\" $proxy.ObfsPassword) \"\") (ne (default \"\" $proxy.HopPorts) \"\") }}?{{- end }}{{- if ne $password \"\" }}auth={{ $password }}{{- end }}{{- if ne $sni \"\" }}{{- if ne $password \"\" }}&{{- end }}sni={{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}{{- if or (ne $password \"\") (ne $sni \"\") }}&{{- end }}insecure=1{{- end }}{{- if ne (default \"\" $proxy.ObfsPassword) \"\" }}{{- if or (ne $password \"\") (ne $sni \"\") $proxy.AllowInsecure }}&{{- end }}obfs=salamander&obfs-password={{ $proxy.ObfsPassword }}{{- end }}{{- if ne (default \"\" $proxy.HopPorts) \"\" }}{{- if or (ne $password \"\") (ne $sni \"\") $proxy.AllowInsecure (ne (default \"\" $proxy.ObfsPassword) \"\") }}&{{- end }}mport={{ $proxy.HopPorts }}{{- end }}{{- if or (ne $password \"\") (ne $sni \"\") $proxy.AllowInsecure (ne (default \"\" $proxy.ObfsPassword) \"\") (ne (default \"\" $proxy.HopPorts) \"\") }}&{{ $common }}{{- else }}?{{ $common }}{{- end }}#{{ $proxy.Name }}\n {{- else if eq $proxy.Type \"tuic\" }}\ntuic://{{ $password }}:{{ $password }}@{{ $server }}:{{ $proxy.Port }}{{- if or (ne (default \"\" $proxy.CongestionController) \"\") (ne (default \"\" $proxy.UDPRelayMode) \"\") $proxy.ReduceRtt $proxy.DisableSNI (ne $sni \"\") $proxy.AllowInsecure }}?{{- end }}{{- if ne (default \"\" $proxy.CongestionController) \"\" }}congestion_controller={{ $proxy.CongestionController }}{{- end }}{{- if ne (default \"\" $proxy.UDPRelayMode) \"\" }}{{- if ne (default \"\" $proxy.CongestionController) \"\" }}&{{- end }}udp_relay_mode={{ $proxy.UDPRelayMode }}{{- end }}{{- if $proxy.ReduceRtt }}{{- if or (ne (default \"\" $proxy.CongestionController) \"\") (ne (default \"\" $proxy.UDPRelayMode) \"\") }}&{{- end }}reduce_rtt=1{{- end }}{{- if $proxy.DisableSNI }}{{- if or (ne (default \"\" $proxy.CongestionController) \"\") (ne (default \"\" $proxy.UDPRelayMode) \"\") $proxy.ReduceRtt }}&{{- end }}disable_sni=1{{- end }}{{- if ne $sni \"\" }}{{- if or (ne (default \"\" $proxy.CongestionController) \"\") (ne (default \"\" $proxy.UDPRelayMode) \"\") $proxy.ReduceRtt $proxy.DisableSNI }}&{{- end }}sni={{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}{{- if or (ne (default \"\" $proxy.CongestionController) \"\") (ne (default \"\" $proxy.UDPRelayMode) \"\") $proxy.ReduceRtt $proxy.DisableSNI (ne $sni \"\") }}&{{- end }}allow_insecure=1{{- end }}{{- if or (ne (default \"\" $proxy.CongestionController) \"\") (ne (default \"\" $proxy.UDPRelayMode) \"\") $proxy.ReduceRtt $proxy.DisableSNI (ne $sni \"\") $proxy.AllowInsecure }}&{{ $common }}{{- else }}?{{ $common }}{{- end }}#{{ $proxy.Name }}\n {{- else if eq $proxy.Type \"anytls\" }}\nanytls://{{ $password }}@{{ $server }}:{{ $proxy.Port }}{{- if ne $sni \"\" }}?sni={{ $sni }}&{{ $common }}{{- else }}?{{ $common }}{{- end }}#{{ $proxy.Name }}\n {{- else }}\n# Unsupported protocol: {{ $proxy.Type }} - {{ $proxy.Name }}\n {{- end }}\n{{- end }}', 'base64', '{}', '2025-08-12 23:03:50.004', '2025-08-15 22:01:39.221'); +INSERT INTO `subscribe_application` (`id`, `name`, `icon`, `description`, `scheme`, `user_agent`, `is_default`, `subscribe_template`, `output_format`, `download_link`, `created_at`, `updated_at`) VALUES (3, 'Clash', '', '', 'clash://install-config?url=${url}&name=${name}', 'Clash', 0, '{{- $GiB := 1073741824.0 -}}\n{{- $used := printf \"%.2f\" (divf (add (.UserInfo.Download | default 0 | float64) (.UserInfo.Upload | default 0 | float64)) $GiB) -}}\n{{- $traffic := (.UserInfo.Traffic | default 0 | float64) -}}\n{{- $total := printf \"%.2f\" (divf $traffic $GiB) -}}\n\n{{- $exp := \"\" -}}\n{{- $expStr := printf \"%v\" .UserInfo.ExpiredAt -}}\n{{- if regexMatch `^[0-9]+$` $expStr -}}\n {{- $ts := $expStr | float64 -}}\n {{- $sec := ternary (divf $ts 1000.0) $ts (ge (len $expStr) 13) -}}\n {{- $exp = (date \"2006-01-02 15:04:05\" (unixEpoch ($sec | int64))) -}}\n{{- else -}}\n {{- $exp = $expStr -}}\n{{- end -}}\n\n{{- $supportedProxies := list -}}\n{{- range $proxy := .Proxies -}}\n {{- if or (eq $proxy.Type \"shadowsocks\") (eq $proxy.Type \"vmess\") (eq $proxy.Type \"vless\") (eq $proxy.Type \"trojan\") (eq $proxy.Type \"hysteria2\") (eq $proxy.Type \"tuic\") -}}\n {{- $supportedProxies = append $supportedProxies $proxy -}}\n {{- end -}}\n{{- end -}}\n\n{{- $proxyNames := \"\" -}}\n{{- range $proxy := $supportedProxies -}}\n {{- if eq $proxyNames \"\" -}}\n {{- $proxyNames = $proxy.Name -}}\n {{- else -}}\n {{- $proxyNames = printf \"%s, %s\" $proxyNames $proxy.Name -}}\n {{- end -}}\n{{- end -}}\n\n# {{ .SiteName }}-{{ .SubscribeName }}\n# Traffic: {{ $used }} GiB/{{ $total }} GiB | Expires: {{ $exp }}\n\nmode: rule\nipv6: true\nallow-lan: true\nbind-address: ''*''\nmixed-port: 6088\nlog-level: error\nunified-delay: true\ntcp-concurrent: true\nexternal-controller: ''0.0.0.0:9090''\ntun:\n enable: true\n stack: system\n auto-route: true\ndns:\n enable: true\n cache-algorithm: arc\n listen: ''0.0.0.0:1053''\n ipv6: true\n enhanced-mode: fake-ip\n fake-ip-range: 198.18.0.1/16\n fake-ip-filter: [''*.lan'', lens.l.google.com, ''*.srv.nintendo.net'', ''*.stun.playstation.net'', ''xbox.*.*.microsoft.com'', ''*.xboxlive.com'', ''*.msftncsi.com'', ''*.msftconnecttest.com'']\n default-nameserver: [119.29.29.29, 223.5.5.5]\n nameserver: [system, 119.29.29.29, 223.5.5.5]\n fallback: [8.8.8.8, 1.1.1.1]\n fallback-filter: { geoip: true, geoip-code: CN }\n\nproxies:\n{{- range $proxy := $supportedProxies }}\n {{- $server := $proxy.Server -}}\n {{- if and (contains $proxy.Server \":\") (not (hasPrefix \"[\" $proxy.Server)) -}}\n {{- $server = printf \"[%s]\" $proxy.Server -}}\n {{- end -}}\n\n {{- $sni := default \"\" $proxy.SNI -}}\n {{- if eq $sni \"\" -}}\n {{- $sni = default \"\" $proxy.Host -}}\n {{- end -}}\n {{- if and (eq $sni \"\") (not (or (regexMatch \"^[0-9]+\\\\.[0-9]+\\\\.[0-9]+\\\\.[0-9]+$\" $proxy.Server) (contains $proxy.Server \":\"))) -}}\n {{- $sni = $proxy.Server -}}\n {{- end -}}\n\n {{- $password := $.UserInfo.Password -}}\n {{- if and (eq $proxy.Type \"shadowsocks\") (ne (default \"\" $proxy.ServerKey) \"\") -}}\n {{- $method := $proxy.Method -}}\n {{- if or (hasPrefix \"2022-blake3-\" $method) (eq $method \"2022-blake3-aes-128-gcm\") (eq $method \"2022-blake3-aes-256-gcm\") -}}\n {{- $userKeyLen := ternary 16 32 (hasSuffix \"128-gcm\" $method) -}}\n {{- $pwdStr := printf \"%s\" $password -}}\n {{- $userKey := ternary $pwdStr (trunc $userKeyLen $pwdStr) (le (len $pwdStr) $userKeyLen) -}}\n {{- $serverB64 := b64enc $proxy.ServerKey -}}\n {{- $userB64 := b64enc $userKey -}}\n {{- $password = printf \"%s:%s\" $serverB64 $userB64 -}}\n {{- end -}}\n {{- end -}}\n\n {{- $common := \"udp: true, tfo: true\" -}}\n\n {{- if eq $proxy.Type \"shadowsocks\" }}\n - { name: {{ $proxy.Name | quote }}, type: ss, server: {{ $server }}, port: {{ $proxy.Port }}, cipher: {{ default \"aes-128-gcm\" $proxy.Method }}, password: {{ $password }}, {{ $common }}{{- if ne (default \"\" $proxy.Transport) \"\" }}, plugin: obfs, plugin-opts: { mode: http, host: {{ $sni }} }{{- end }} }\n {{- else if eq $proxy.Type \"vmess\" }}\n - { name: {{ $proxy.Name | quote }}, type: vmess, server: {{ $server }}, port: {{ $proxy.Port }}, uuid: {{ $password }}, alterId: 0, cipher: auto, {{ $common }}{{- if or (eq $proxy.Transport \"websocket\") (eq $proxy.Transport \"ws\") }}, network: ws, ws-opts: { path: {{ default \"/\" $proxy.Path }}{{- if ne (default \"\" $proxy.Host) \"\" }}, headers: { Host: {{ $proxy.Host }} }{{- end }} }{{- else if eq $proxy.Transport \"http\" }}, network: http, http-opts: { method: GET, path: [{{ default \"/\" $proxy.Path | quote }}]{{- if ne (default \"\" $proxy.Host) \"\" }}, headers: { Host: [{{ $proxy.Host | quote }}] }{{- end }} }{{- else if eq $proxy.Transport \"grpc\" }}, network: grpc, grpc-opts: { grpc-service-name: {{ default \"grpc\" $proxy.ServiceName }} }{{- end }}{{- if or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\") }}, tls: true{{- end }}{{- if ne $sni \"\" }}, servername: {{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify: true{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}, fingerprint: {{ $proxy.Fingerprint }}{{- end }} }\n {{- else if eq $proxy.Type \"vless\" }}\n - { name: {{ $proxy.Name | quote }}, type: vless, server: {{ $server }}, port: {{ $proxy.Port }}, uuid: {{ $password }}, {{ $common }}{{- if or (eq $proxy.Transport \"ws\") (eq $proxy.Transport \"websocket\") }}, network: ws, ws-opts: { path: {{ default \"/\" $proxy.Path }}{{- if ne (default \"\" $proxy.Host) \"\" }}, headers: { Host: {{ $proxy.Host }} }{{- end }} }{{- else if eq $proxy.Transport \"http\" }}, network: http, http-opts: { method: GET, path: [{{ default \"/\" $proxy.Path | quote }}]{{- if ne (default \"\" $proxy.Host) \"\" }}, headers: { Host: [{{ $proxy.Host | quote }}] }{{- end }} }{{- else if eq $proxy.Transport \"grpc\" }}, network: grpc, grpc-opts: { grpc-service-name: {{ default \"grpc\" $proxy.ServiceName }} }{{- end }}{{- if ne $sni \"\" }}, servername: {{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify: true{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}, fingerprint: {{ $proxy.Fingerprint }}{{- end }}{{- if and (eq $proxy.Security \"reality\") (ne (default \"\" $proxy.RealityPublicKey) \"\") }}, reality-opts: { public-key: {{ $proxy.RealityPublicKey }}{{- if ne (default \"\" $proxy.RealityShortId) \"\" }}, short-id: {{ $proxy.RealityShortId }}{{- end }} }{{- end }}{{- if ne (default \"\" $proxy.Flow) \"\" }}, flow: {{ $proxy.Flow }}{{- end }} }\n {{- else if eq $proxy.Type \"trojan\" }}\n - { name: {{ $proxy.Name | quote }}, type: trojan, server: {{ $server }}, port: {{ $proxy.Port }}, password: {{ $password }}, {{ $common }}{{- if ne $sni \"\" }}, sni: {{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify: true{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}, fingerprint: {{ $proxy.Fingerprint }}{{- end }}{{- if or (eq $proxy.Transport \"ws\") (eq $proxy.Transport \"websocket\") }}, network: ws, ws-opts: { path: {{ default \"/\" $proxy.Path }}{{- if ne (default \"\" $proxy.Host) \"\" }}, headers: { Host: {{ $proxy.Host }} }{{- end }} }{{- else if eq $proxy.Transport \"http\" }}, network: http, http-opts: { method: GET, path: [{{ default \"/\" $proxy.Path | quote }}]{{- if ne (default \"\" $proxy.Host) \"\" }}, headers: { Host: [{{ $proxy.Host | quote }}] }{{- end }} }{{- else if eq $proxy.Transport \"grpc\" }}, network: grpc, grpc-opts: { grpc-service-name: {{ default \"grpc\" $proxy.ServiceName }} }{{- end }} }\n {{- else if or (eq $proxy.Type \"hysteria2\") (eq $proxy.Type \"hy2\") }}\n - { name: {{ $proxy.Name | quote }}, type: hysteria2, server: {{ $server }}, port: {{ $proxy.Port }}, password: {{ $password }}, {{ $common }}{{- if ne $sni \"\" }}, sni: {{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify: true{{- end }}{{- if ne (default \"\" $proxy.ObfsPassword) \"\" }}, obfs: salamander, obfs-password: {{ $proxy.ObfsPassword }}{{- end }}{{- if ne (default \"\" $proxy.HopPorts) \"\" }}, ports: {{ $proxy.HopPorts }}{{- end }}{{- if ne (default 0 $proxy.HopInterval) 0 }}, hop-interval: {{ $proxy.HopInterval }}{{- end }} }\n {{- else if eq $proxy.Type \"tuic\" }}\n - { name: {{ $proxy.Name | quote }}, type: tuic, server: {{ $server }}, port: {{ $proxy.Port }}, uuid: {{ default \"\" $proxy.ServerKey }}, password: {{ $password }}, {{ $common }}{{- if ne $sni \"\" }}, sni: {{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify: true{{- end }}{{- if $proxy.DisableSNI }}, disable-sni: true{{- end }}{{- if $proxy.ReduceRtt }}, reduce-rtt: true{{- end }}{{- if ne (default \"\" $proxy.UDPRelayMode) \"\" }}, udp-relay-mode: {{ $proxy.UDPRelayMode }}{{- end }}{{- if ne (default \"\" $proxy.CongestionController) \"\" }}, congestion-controller: {{ $proxy.CongestionController }}{{- end }} }\n {{- else if eq $proxy.Type \"wireguard\" }}\n - { name: {{ $proxy.Name | quote }}, type: wireguard, server: {{ $server }}, port: {{ $proxy.Port }}, private-key: {{ default \"\" $proxy.ServerKey }}, public-key: {{ default \"\" $proxy.RealityPublicKey }}, {{ $common }}{{- if ne (default \"\" $proxy.Path) \"\" }}, preshared-key: {{ $proxy.Path }}{{- end }}{{- if ne (default \"\" $proxy.RealityServerAddr) \"\" }}, ip: {{ $proxy.RealityServerAddr }}{{- end }}{{- if ne (default 0 $proxy.RealityServerPort) 0 }}, ipv6: {{ $proxy.RealityServerPort }}{{- end }} }\n {{- else if eq $proxy.Type \"anytls\" }}\n - { name: {{ $proxy.Name | quote }}, type: anytls, server: {{ $server }}, port: {{ $proxy.Port }}, password: {{ $password }}, {{ $common }} }\n {{- else }}\n - { name: {{ $proxy.Name | quote }}, type: {{ $proxy.Type }}, server: {{ $server }}, port: {{ $proxy.Port }}, {{ $common }} }\n {{- end }}\n{{- end }}\n\n{{- range $proxy := .Proxies }}\n {{- if not (or (eq $proxy.Type \"shadowsocks\") (eq $proxy.Type \"vmess\") (eq $proxy.Type \"vless\") (eq $proxy.Type \"trojan\") (eq $proxy.Type \"hysteria2\") (eq $proxy.Type \"tuic\")) }}\n# Skipped (unsupported by Clash): {{ $proxy.Name }} ({{ $proxy.Type }})\n {{- end }}\n{{- end }}\n\nproxy-groups:\n - { name: 🚀 Proxy, type: select, proxies: [🌏 Auto, 🎯 Direct, {{ $proxyNames }}] }\n - { name: 🍎 Apple, type: select, proxies: [🚀 Proxy, 🎯 Direct, {{ $proxyNames }}] }\n - { name: 🔍 Google, type: select, proxies: [🚀 Proxy, 🎯 Direct, {{ $proxyNames }}] }\n - { name: 🪟 Microsoft, type: select, proxies: [🚀 Proxy, 🎯 Direct, {{ $proxyNames }}] }\n - { name: 📺 GlobalMedia, type: select, proxies: [🚀 Proxy, 🎯 Direct, {{ $proxyNames }}] }\n - { name: 📟 Telegram, type: select, proxies: [🚀 Proxy, 🎯 Direct, {{ $proxyNames }}] }\n - { name: 🤖 AI, type: select, proxies: [🚀 Proxy, 🎯 Direct, {{ $proxyNames }}] }\n - { name: 🪙 Crypto, type: select, proxies: [🚀 Proxy, 🎯 Direct, {{ $proxyNames }}] }\n - { name: 🎮 Game, type: select, proxies: [🚀 Proxy, 🎯 Direct, {{ $proxyNames }}] }\n - { name: 🇨🇳 China, type: select, proxies: [🎯 Direct, 🚀 Proxy, {{ $proxyNames }}] }\n - { name: 🎯 Direct, type: select, proxies: [DIRECT], hidden: true }\n - { name: 🐠 Final, type: select, proxies: [🚀 Proxy, 🎯 Direct, {{ $proxyNames }}] }\n - { name: 🌏 Auto, type: url-test, proxies: [{{ $proxyNames }}] }\n\nrules:\n - RULE-SET, Apple, 🍎 Apple\n - RULE-SET, Google, 🔍 Google\n - RULE-SET, Microsoft, 🪟 Microsoft\n - RULE-SET, Github, 🪟 Microsoft\n - RULE-SET, HBO, 📺 GlobalMedia\n - RULE-SET, Disney, 📺 GlobalMedia\n - RULE-SET, TikTok, 📺 GlobalMedia\n - RULE-SET, Netflix, 📺 GlobalMedia\n - RULE-SET, GlobalMedia, 📺 GlobalMedia\n - RULE-SET, Telegram, 📟 Telegram\n - RULE-SET, OpenAI, 🤖 AI\n - RULE-SET, Gemini, 🤖 AI\n - RULE-SET, Copilot, 🤖 AI\n - RULE-SET, Claude, 🤖 AI\n - RULE-SET, Crypto, 🪙 Crypto\n - RULE-SET, Cryptocurrency, 🪙 Crypto\n - RULE-SET, Game, 🎮 Game\n - RULE-SET, Global, 🚀 Proxy\n - RULE-SET, ChinaMax, 🇨🇳 China\n - RULE-SET, Lan, 🎯 Direct\n - GEOIP, CN, 🇨🇳 China\n - MATCH, 🐠 Final\n\nrule-providers:\n Apple:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Apple/Apple_Classical_No_Resolve.yaml\n interval: 86400\n Google:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Google/Google_No_Resolve.yaml\n interval: 86400\n Microsoft:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Microsoft/Microsoft.yaml\n interval: 86400\n Github:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/GitHub/GitHub.yaml\n interval: 86400\n HBO:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/HBO/HBO.yaml\n interval: 86400\n Disney:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Disney/Disney.yaml\n interval: 86400\n TikTok:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/TikTok/TikTok.yaml\n interval: 86400\n Netflix:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Netflix/Netflix.yaml\n interval: 86400\n GlobalMedia:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/GlobalMedia/GlobalMedia_Classical_No_Resolve.yaml\n interval: 86400\n Telegram:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Telegram/Telegram_No_Resolve.yaml\n interval: 86400\n OpenAI:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/OpenAI/OpenAI.yaml\n interval: 86400\n Gemini:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Gemini/Gemini.yaml\n interval: 86400\n Copilot:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Copilot/Copilot.yaml\n interval: 86400\n Claude:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Claude/Claude.yaml\n interval: 86400\n Crypto:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Crypto/Crypto.yaml\n interval: 86400\n Cryptocurrency:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Cryptocurrency/Cryptocurrency.yaml\n interval: 86400\n Game:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Game/Game.yaml\n interval: 86400\n Global:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Global/Global_Classical_No_Resolve.yaml\n interval: 86400\n ChinaMax:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/ChinaMax/ChinaMax_Classical_No_Resolve.yaml\n interval: 86400\n Lan:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Lan/Lan.yaml\n interval: 86400\n\nurl-rewrite:\n - ^https?:\\/\\/(www.)?g\\.cn https://www.google.com 302\n - ^https?:\\/\\/(www.)?google\\.cn https://www.google.com 302\n', 'yaml', '{}', '2025-08-12 23:10:00.487', '2025-08-15 22:01:27.031'); +INSERT INTO `subscribe_application` (`id`, `name`, `icon`, `description`, `scheme`, `user_agent`, `is_default`, `subscribe_template`, `output_format`, `download_link`, `created_at`, `updated_at`) VALUES (4, 'SingBox', '', '', 'sing-box://import-remote-profile?url=${encodeURIComponent(url)}#${name}', 'sing-box', 0, '{{- $GiB := 1073741824.0 -}}\n{{- $used := printf \"%.2f\" (divf (add (.UserInfo.Download | default 0 | float64) (.UserInfo.Upload | default 0 | float64)) $GiB) -}}\n{{- $traffic := (.UserInfo.Traffic | default 0 | float64) -}}\n{{- $total := printf \"%.2f\" (divf $traffic $GiB) -}}\n\n{{- $exp := \"\" -}}\n{{- $expStr := printf \"%v\" .UserInfo.ExpiredAt -}}\n{{- if regexMatch `^[0-9]+$` $expStr -}}\n {{- $ts := $expStr | float64 -}}\n {{- $sec := ternary (divf $ts 1000.0) $ts (ge (len $expStr) 13) -}}\n {{- $exp = (date \"2006-01-02 15:04:05\" (unixEpoch ($sec | int64))) -}}\n{{- else -}}\n {{- $exp = $expStr -}}\n{{- end -}}\n\n{{- $supportedProxies := list -}}\n{{- range $proxy := .Proxies -}}\n {{- if or (eq $proxy.Type \"shadowsocks\") (eq $proxy.Type \"vmess\") (eq $proxy.Type \"vless\") (eq $proxy.Type \"trojan\") (eq $proxy.Type \"hysteria2\") (eq $proxy.Type \"hy2\") (eq $proxy.Type \"tuic\") -}}\n {{- $supportedProxies = append $supportedProxies $proxy -}}\n {{- end -}}\n{{- end -}}\n\n{{- $proxyNames := \"\" -}}\n{{- if gt (len $supportedProxies) 0 -}}\n {{- range $proxy := $supportedProxies -}}\n {{- if eq $proxyNames \"\" -}}\n {{- $proxyNames = printf \"\\\"%s\\\"\" $proxy.Name -}}\n {{- else -}}\n {{- $proxyNames = printf \"%s, \\\"%s\\\"\" $proxyNames $proxy.Name -}}\n {{- end -}}\n {{- end -}}\n {{- $proxyNames = printf \", %s\" $proxyNames -}}\n{{- end -}}\n\n\n{\n \"log\": {\"level\": \"info\", \"timestamp\": true},\n \"experimental\": {\n \"cache_file\": {\"enabled\": true, \"path\": \"cache.db\", \"cache_id\": \"my_profile\", \"store_fakeip\": false},\n \"clash_api\": {\"external_controller\": \"127.0.0.1:9090\", \"external_ui\": \"ui\", \"secret\": \"\", \"external_ui_download_url\": \"https://mirror.ghproxy.com/https://github.com/MetaCubeX/Yacd-meta/archive/gh-pages.zip\", \"external_ui_download_detour\": \"direct\", \"default_mode\": \"rule\"}\n },\n \"dns\": {\n \"servers\": [\n {\"tag\": \"dns_proxy\",\"address\": \"tls://8.8.8.8\",\"detour\": \"Proxy\"},\n {\"tag\": \"dns_direct\",\"address\": \"https://223.5.5.5/dns-query\",\"detour\": \"direct\"}\n ],\n \"rules\": [\n {\"rule_set\": \"geosite-cn\", \"server\": \"dns_direct\"},\n {\"clash_mode\": \"direct\", \"server\": \"dns_direct\"},\n {\"clash_mode\": \"global\", \"server\": \"dns_proxy\"},\n {\"rule_set\": \"geosite-geolocation-!cn\", \"server\": \"dns_proxy\"}\n ],\n \"final\": \"dns_direct\",\n \"strategy\": \"ipv4_only\"\n },\n \"inbounds\": [\n {\"tag\": \"tun-in\", \"type\": \"tun\", \"address\": [\"172.18.0.1/30\",\"fdfe:dcba:9876::1/126\"], \"auto_route\": true, \"strict_route\": true, \"stack\": \"system\",\n \"platform\": {\"http_proxy\": {\"enabled\": true, \"server\": \"127.0.0.1\", \"server_port\": 7890}}},\n {\"tag\": \"mixed-in\", \"type\": \"mixed\", \"listen\": \"127.0.0.1\", \"listen_port\": 7890}\n ],\n \"outbounds\": [\n {\"tag\": \"Proxy\", \"type\": \"selector\", \"outbounds\": [\"Auto - UrlTest\", \"direct\"{{ $proxyNames }}]},\n {\"tag\": \"Domestic\", \"type\": \"selector\", \"outbounds\": [\"direct\", \"Proxy\"{{ $proxyNames }}]},\n {\"tag\": \"Others\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ $proxyNames }}]},\n {\"tag\": \"AI Suite\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ $proxyNames }}]},\n {\"tag\": \"Netflix\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ $proxyNames }}]},\n {\"tag\": \"Disney Plus\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ $proxyNames }}]},\n {\"tag\": \"YouTube\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ $proxyNames }}]},\n {\"tag\": \"Max\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ $proxyNames }}]},\n {\"tag\": \"Spotify\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ $proxyNames }}]},\n {\"tag\": \"Apple\", \"type\": \"selector\", \"outbounds\": [\"direct\", \"Proxy\"{{ $proxyNames }}]},\n {\"tag\": \"Telegram\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ $proxyNames }}]},\n {\"tag\": \"Microsoft\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ $proxyNames }}]},\n {\"tag\": \"Tiktok\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ $proxyNames }}]},\n {\"tag\": \"AdBlock\", \"type\": \"selector\", \"outbounds\": [\"block\", \"direct\", \"Proxy\"]},\n {{- if gt (len $supportedProxies) 0 }}\n {\"tag\": \"Auto - UrlTest\", \"type\": \"urltest\", \"outbounds\": [{{ $proxyNames | trimPrefix \", \" }}], \"url\": \"http://cp.cloudflare.com/\", \"interval\": \"10m\", \"tolerance\": 50}\n {{- range $i, $proxy := $supportedProxies }},\n{{- $server := $proxy.Server -}}\n{{- if and (contains $proxy.Server \":\") (not (hasPrefix \"[\" $proxy.Server)) -}}\n {{- $server = printf \"[%s]\" $proxy.Server -}}\n{{- end -}}\n\n{{- $sni := default \"\" $proxy.SNI -}}\n{{- if eq $sni \"\" -}}\n {{- $sni = default \"\" $proxy.Host -}}\n{{- end -}}\n{{- if and (eq $sni \"\") (not (or (regexMatch \"^[0-9]+\\\\.[0-9]+\\\\.[0-9]+\\\\.[0-9]+$\" $proxy.Server) (contains $proxy.Server \":\"))) -}}\n {{- $sni = $proxy.Server -}}\n{{- end -}}\n\n{{- $password := $.UserInfo.Password -}}\n{{- if and (eq $proxy.Type \"shadowsocks\") (ne (default \"\" $proxy.ServerKey) \"\") -}}\n {{- $method := $proxy.Method -}}\n {{- if or (hasPrefix \"2022-blake3-\" $method) (eq $method \"2022-blake3-aes-128-gcm\") (eq $method \"2022-blake3-aes-256-gcm\") -}}\n {{- $userKeyLen := ternary 16 32 (hasSuffix \"128-gcm\" $method) -}}\n {{- $pwdStr := printf \"%s\" $password -}}\n {{- $userKey := ternary $pwdStr (trunc $userKeyLen $pwdStr) (le (len $pwdStr) $userKeyLen) -}}\n {{- $serverB64 := b64enc $proxy.ServerKey -}}\n {{- $userB64 := b64enc $userKey -}}\n {{- $password = printf \"%s:%s\" $serverB64 $userB64 -}}\n {{- end -}}\n{{- end -}}\n\n{{- $common := `\"tcp_fast_open\": true, \"udp_over_tcp\": false` -}}\n\n{{- if eq $proxy.Type \"shadowsocks\" -}}\n {{- $method := default \"aes-128-gcm\" $proxy.Method -}}\n { \"type\": \"shadowsocks\", \"tag\": {{ $proxy.Name | quote }}, \"server\": {{ $server | quote }}, \"server_port\": {{ $proxy.Port }}, \"method\": {{ $method | quote }}, \"password\": {{ $password | quote }}, {{ $common }} }\n{{- else if eq $proxy.Type \"trojan\" -}}\n { \"type\": \"trojan\", \"tag\": {{ $proxy.Name | quote }}, \"server\": {{ $server | quote }}, \"server_port\": {{ $proxy.Port }}, \"password\": {{ $password | quote }}{{- if or (eq $proxy.Transport \"ws\") (eq $proxy.Transport \"websocket\") }}, \"transport\": {\"type\": \"ws\", \"path\": {{ default \"/\" $proxy.Path | quote }}{{- if ne (default \"\" $proxy.Host) \"\" }}, \"headers\": {\"Host\": {{ $proxy.Host | quote }} }{{- end -}}}{{- else if eq $proxy.Transport \"grpc\" }}, \"transport\": {\"type\": \"grpc\", \"service_name\": {{ default \"grpc\" $proxy.ServiceName | quote }}}{{- end }}, {{ $common }}, \"tls\": {\"enabled\": true{{- if ne $sni \"\" }}, \"server_name\": {{ $sni | quote }}{{- end }}{{- if $proxy.AllowInsecure }}, \"insecure\": true{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}, \"utls\": {\"enabled\": true, \"fingerprint\": {{ $proxy.Fingerprint | quote }} }{{- end }}} }\n{{- else if eq $proxy.Type \"vless\" -}}\n { \"type\": \"vless\", \"tag\": {{ $proxy.Name | quote }}, \"server\": {{ $server | quote }}, \"server_port\": {{ $proxy.Port }}, \"uuid\": {{ $password | quote }}{{- if ne (default \"\" $proxy.Flow) \"\" }}, \"flow\": {{ $proxy.Flow | quote }}{{- end }}{{- if or (eq $proxy.Transport \"ws\") (eq $proxy.Transport \"websocket\") }}, \"transport\": {\"type\": \"ws\", \"path\": {{ default \"/\" $proxy.Path | quote }}{{- if ne (default \"\" $proxy.Host) \"\" }}, \"headers\": {\"Host\": {{ $proxy.Host | quote }} }{{- end -}}}{{- else if eq $proxy.Transport \"grpc\" }}, \"transport\": {\"type\": \"grpc\", \"service_name\": {{ default \"grpc\" $proxy.ServiceName | quote }}}{{- end }}, {{ $common }}{{- if ne (default \"\" $proxy.RealityPublicKey) \"\" }}, \"reality\": { \"enabled\": true, \"public_key\": {{ $proxy.RealityPublicKey | quote }}{{- if ne (default \"\" $proxy.RealityShortId) \"\" }}, \"short_id\": {{ $proxy.RealityShortId | quote }}{{- end }}{{- if ne $sni \"\" }}, \"server_name\": {{ $sni | quote }}{{- end }} }{{- else if or (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\") $proxy.AllowInsecure (ne (default \"\" $proxy.Fingerprint) \"\") }}, \"tls\": {\"enabled\": true{{- if ne $sni \"\" }}, \"server_name\": {{ $sni | quote }}{{- end }}{{- if $proxy.AllowInsecure }}, \"insecure\": true{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}, \"utls\": {\"enabled\": true, \"fingerprint\": {{ $proxy.Fingerprint | quote }} }{{- end }}}{{- end }} }\n{{- else if eq $proxy.Type \"vmess\" -}}\n { \"type\": \"vmess\", \"tag\": {{ $proxy.Name | quote }}, \"server\": {{ $server | quote }}, \"server_port\": {{ $proxy.Port }}, \"uuid\": {{ $password | quote }}, \"security\": \"auto\", {{ $common }}{{- if or (eq $proxy.Transport \"ws\") (eq $proxy.Transport \"websocket\") }}, \"transport\": {\"type\": \"ws\", \"path\": {{ default \"/\" $proxy.Path | quote }}{{- if ne (default \"\" $proxy.Host) \"\" }}, \"headers\": {\"Host\": {{ $proxy.Host | quote }} }{{- end -}}}{{- else if eq $proxy.Transport \"grpc\" }}, \"transport\": {\"type\": \"grpc\", \"service_name\": {{ default \"grpc\" $proxy.ServiceName | quote }}}{{- end }}{{- if or (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\") $proxy.AllowInsecure (ne (default \"\" $proxy.Fingerprint) \"\") }}, \"tls\": {\"enabled\": true{{- if ne $sni \"\" }}, \"server_name\": {{ $sni | quote }}{{- end }}{{- if $proxy.AllowInsecure }}, \"insecure\": true{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}, \"utls\": {\"enabled\": true, \"fingerprint\": {{ $proxy.Fingerprint | quote }} }{{- end }}}{{- end }} }\n{{- else if or (eq $proxy.Type \"hysteria2\") (eq $proxy.Type \"hy2\") -}}\n { \"type\": \"hysteria2\", \"tag\": {{ $proxy.Name | quote }}, \"server\": {{ $server | quote }}, \"server_port\": {{ $proxy.Port }}, \"password\": {{ $password | quote }}{{- if ne (default \"\" $proxy.ObfsPassword) \"\" }}, \"obfs\": { \"type\": \"salamander\", \"password\": {{ $proxy.ObfsPassword | quote }} }{{- end }}{{- if ne (default \"\" $proxy.HopPorts) \"\" }}, \"ports\": {{ $proxy.HopPorts | quote }}{{- end }}{{- if ne (default 0 $proxy.HopInterval) 0 }}, \"hop_interval\": {{ $proxy.HopInterval }}{{- end }}, {{ $common }}, \"tls\": {\"enabled\": true{{- if ne $sni \"\" }}, \"server_name\": {{ $sni | quote }}{{- end }}{{- if $proxy.AllowInsecure }}, \"insecure\": true{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}, \"utls\": {\"enabled\": true, \"fingerprint\": {{ $proxy.Fingerprint | quote }} }{{- end }}} }\n{{- else if eq $proxy.Type \"tuic\" -}}\n { \"type\": \"tuic\", \"tag\": {{ $proxy.Name | quote }}, \"server\": {{ $server | quote }}, \"server_port\": {{ $proxy.Port }}, \"uuid\": {{ default \"\" $proxy.ServerKey | quote }}, \"password\": {{ $password | quote }}{{- if $proxy.DisableSNI }}, \"disable_sni\": true{{- end }}{{- if $proxy.ReduceRtt }}, \"reduce_rtt\": true{{- end }}{{- if ne (default \"\" $proxy.UDPRelayMode) \"\" }}, \"udp_relay_mode\": {{ $proxy.UDPRelayMode | quote }}{{- end }}{{- if ne (default \"\" $proxy.CongestionController) \"\" }}, \"congestion_control\": {{ $proxy.CongestionController | quote }}{{- end }}, {{ $common }}, \"alpn\": [\"h3\"], \"tls\": {\"enabled\": true{{- if ne $sni \"\" }}, \"server_name\": {{ $sni | quote }}{{- end }}{{- if $proxy.AllowInsecure }}, \"insecure\": true{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}, \"utls\": {\"enabled\": true, \"fingerprint\": {{ $proxy.Fingerprint | quote }} }{{- end }}} }\n{{- else if eq $proxy.Type \"anytls\" -}}\n { \"type\": \"anytls\", \"tag\": {{ $proxy.Name | quote }}, \"server\": {{ $server | quote }}, \"server_port\": {{ $proxy.Port }}, \"password\": {{ $password | quote }}, {{ $common }}, \"tls\": {\"enabled\": true{{- if ne $sni \"\" }}, \"server_name\": {{ $sni | quote }}{{- end }}{{- if $proxy.AllowInsecure }}, \"insecure\": true{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}, \"utls\": {\"enabled\": true, \"fingerprint\": {{ $proxy.Fingerprint | quote }} }{{- end }}} }\n{{- else if eq $proxy.Type \"wireguard\" -}}\n { \"type\": \"wireguard\", \"tag\": {{ $proxy.Name | quote }}, \"server\": {{ $server | quote }}, \"server_port\": {{ $proxy.Port }}, \"private_key\": {{ default \"\" $proxy.ServerKey | quote }}, \"peer_public_key\": {{ default \"\" $proxy.RealityPublicKey | quote }}{{- if ne (default \"\" $proxy.Path) \"\" }}, \"pre_shared_key\": {{ $proxy.Path | quote }}{{- end }}{{- if ne (default \"\" $proxy.RealityServerAddr) \"\" }}, \"local_address\": [{{ $proxy.RealityServerAddr | quote }}]{{- end }}, {{ $common }} }\n{{- else -}}\n { \"type\": \"direct\", \"tag\": {{ $proxy.Name | quote }}, {{ $common }} }\n{{- end }}\n {{- end }},\n {{- end }}\n {\"type\": \"direct\", \"tag\": \"direct\"},\n {\"type\": \"block\", \"tag\": \"block\"}\n ],\n \"route\": {\n \"auto_detect_interface\": true, \"final\": \"Proxy\",\n \"rules\": [\n {\"type\": \"logical\", \"mode\": \"or\", \"rules\": [{\"port\": 53},{\"protocol\": \"dns\"}], \"action\": \"hijack-dns\"},\n {\"rule_set\": \"geosite-category-ads-all\", \"outbound\": \"AdBlock\"},\n {\"clash_mode\": \"direct\", \"outbound\": \"direct\"},\n {\"clash_mode\": \"global\", \"outbound\": \"Proxy\"},\n {\"domain\": [\"clash.razord.top\",\"yacd.metacubex.one\",\"yacd.haishan.me\",\"d.metacubex.one\"], \"outbound\": \"direct\"},\n {\"ip_is_private\": true, \"outbound\": \"direct\"},\n {\"rule_set\": [\"geoip-netflix\",\"geosite-netflix\"], \"outbound\": \"Netflix\"},\n {\"rule_set\": \"geosite-disney\", \"outbound\": \"Disney Plus\"},\n {\"rule_set\": \"geosite-youtube\", \"outbound\": \"YouTube\"},\n {\"rule_set\": \"geosite-max\", \"outbound\": \"Max\"},\n {\"rule_set\": \"geosite-spotify\", \"outbound\": \"Spotify\"},\n {\"rule_set\": [\"geoip-apple\",\"geosite-apple\"], \"outbound\": \"Apple\"},\n {\"rule_set\": [\"geoip-telegram\",\"geosite-telegram\"], \"outbound\": \"Telegram\"},\n {\"rule_set\": \"geosite-openai\", \"outbound\": \"AI Suite\"},\n {\"rule_set\": \"geosite-microsoft\", \"outbound\": \"Microsoft\"},\n {\"rule_set\": \"geosite-tiktok\", \"outbound\": \"Tiktok\"},\n {\"rule_set\": \"geosite-private\", \"outbound\": \"direct\"},\n {\"rule_set\": [\"geoip-cn\",\"geosite-cn\"], \"outbound\": \"Domestic\"},\n {\"rule_set\": \"geosite-geolocation-!cn\", \"outbound\": \"Others\"}\n ],\n \"rule_set\": [\n {\"tag\": \"geoip-cn\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geoip/cn.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-cn\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/cn.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-private\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/private.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-geolocation-!cn\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/geolocation-!cn.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-category-ads-all\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/category-ads-all.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geoip-netflix\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geoip/netflix.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-netflix\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/netflix.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-disney\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/disney.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-youtube\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/youtube.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-max\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/hbomax.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-spotify\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/spotify.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geoip-apple\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo-lite/geoip/apple.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-apple\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/apple.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geoip-telegram\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geoip/telegram.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-telegram\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/telegram.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-openai\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/openai.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-microsoft\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/microsoft.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-tiktok\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/tiktok.srs\",\"download_detour\": \"direct\"}\n ]\n }\n}\n', 'json', '{}', '2025-08-12 23:30:10.016', '2025-08-15 22:01:10.801'); +INSERT INTO `subscribe_application` (`id`, `name`, `icon`, `description`, `scheme`, `user_agent`, `is_default`, `subscribe_template`, `output_format`, `download_link`, `created_at`, `updated_at`) VALUES (5, 'Surge', '', '', 'surge:///install-config?url=${encodeURIComponent(url)}', 'Surge', 0, '{{- $GiB := 1073741824.0 -}}\n{{- $used := printf \"%.2f\" (divf (add (.UserInfo.Download | default 0 | float64) (.UserInfo.Upload | default 0 | float64)) $GiB) -}}\n{{- $traffic := (.UserInfo.Traffic | default 0 | float64) -}}\n{{- $total := printf \"%.2f\" (divf $traffic $GiB) -}}\n\n{{- $exp := \"\" -}}\n{{- $expStr := printf \"%v\" .UserInfo.ExpiredAt -}}\n{{- if regexMatch `^[0-9]+$` $expStr -}}\n {{- $ts := $expStr | float64 -}}\n {{- $sec := ternary (divf $ts 1000.0) $ts (ge (len $expStr) 13) -}}\n {{- $exp = (date \"2006-01-02 15:04:05\" (unixEpoch ($sec | int64))) -}}\n{{- else -}}\n {{- $exp = $expStr -}}\n{{- end -}}\n\n{{- $supportedProxies := list -}}\n{{- range $proxy := .Proxies -}}\n {{- if or (eq $proxy.Type \"shadowsocks\") (eq $proxy.Type \"vmess\") (eq $proxy.Type \"trojan\") (eq $proxy.Type \"hysteria2\") (eq $proxy.Type \"tuic\") -}}\n {{- $supportedProxies = append $supportedProxies $proxy -}}\n {{- end -}}\n{{- end -}}\n\n{{- $proxyNames := \"\" -}}\n{{- range $proxy := $supportedProxies -}}\n {{- if eq $proxyNames \"\" -}}\n {{- $proxyNames = $proxy.Name -}}\n {{- else -}}\n {{- $proxyNames = printf \"%s, %s\" $proxyNames $proxy.Name -}}\n {{- end -}}\n{{- end -}}\n\n#!MANAGED-CONFIG {{ .UserInfo.SubscribeURL }} interval=86400\n\n[General]\nloglevel = notify\nexternal-controller-access = perlnk@0.0.0.0:6170\nexclude-simple-hostnames = true\nshow-error-page-for-reject = true\nudp-priority = true\nudp-policy-not-supported-behaviour = reject\nipv6 = true\nipv6-vif = auto\nproxy-test-url = http://www.gstatic.com/generate_204\ninternet-test-url = http://connectivitycheck.platform.hicloud.com/generate_204\ntest-timeout = 5\ndns-server = system, 119.29.29.29, 223.5.5.5\nencrypted-dns-server = https://dns.alidns.com/dns-query\nhijack-dns = 8.8.8.8:53, 8.8.4.4:53, 1.1.1.1:53, 1.0.0.1:53\nskip-proxy = 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12, 127.0.0.0/8, localhost, *.local\nalways-real-ip = *.lan, lens.l.google.com, *.srv.nintendo.net, *.stun.playstation.net, *.xboxlive.com, xbox.*.*.microsoft.com, *.msftncsi.com, *.msftconnecttest.com\n\n# > Surge Mac Parameters\nhttp-listen = 0.0.0.0:6088\nsocks5-listen = 0.0.0.0:6089\n\n# > Surge iOS Parameters\nallow-wifi-access = true\nallow-hotspot-access = true\nwifi-access-http-port = 6088\nwifi-access-socks5-port = 6089\n\n[Panel]\nSubscribeInfo = title={{ .SiteName }} - {{ .SubscribeName }}, content=官方网站: perlnk.com \\n已用流量: {{ $used }} GiB/{{ $total }} GiB \\n到期时间: {{ $exp }}, style=info\n\n[Proxy]\n{{- range $proxy := $supportedProxies }}\n {{- $server := $proxy.Server -}}\n {{- if and (contains $proxy.Server \":\") (not (hasPrefix \"[\" $proxy.Server)) -}}\n {{- $server = printf \"[%s]\" $proxy.Server -}}\n {{- end -}}\n\n {{- $sni := default \"\" $proxy.SNI -}}\n {{- if eq $sni \"\" -}}\n {{- $sni = default \"\" $proxy.Host -}}\n {{- end -}}\n {{- if and (eq $sni \"\") (not (or (regexMatch \"^[0-9]+\\\\.[0-9]+\\\\.[0-9]+\\\\.[0-9]+$\" $proxy.Server) (contains $proxy.Server \":\"))) -}}\n {{- $sni = $proxy.Server -}}\n {{- end -}}\n\n {{- $password := $.UserInfo.Password -}}\n {{- if and (eq $proxy.Type \"shadowsocks\") (ne (default \"\" $proxy.ServerKey) \"\") -}}\n {{- $method := $proxy.Method -}}\n {{- if or (hasPrefix \"2022-blake3-\" $method) (eq $method \"2022-blake3-aes-128-gcm\") (eq $method \"2022-blake3-aes-256-gcm\") -}}\n {{- $userKeyLen := ternary 16 32 (hasSuffix \"128-gcm\" $method) -}}\n {{- $pwdStr := printf \"%s\" $password -}}\n {{- $userKey := ternary $pwdStr (trunc $userKeyLen $pwdStr) (le (len $pwdStr) $userKeyLen) -}}\n {{- $serverB64 := b64enc $proxy.ServerKey -}}\n {{- $userB64 := b64enc $userKey -}}\n {{- $password = printf \"%s:%s\" $serverB64 $userB64 -}}\n {{- end -}}\n {{- end -}}\n\n {{- $common := \"udp-relay=true, tfo=true\" -}}\n\n {{- if eq $proxy.Type \"shadowsocks\" }}\n{{ $proxy.Name }} = ss, {{ $server }}, {{ $proxy.Port }}, encrypt-method={{ default \"aes-128-gcm\" $proxy.Method }}, password={{ $password }}{{- if ne (default \"\" $proxy.Transport) \"\" }}, obfs={{ $proxy.Transport }}, obfs-host={{ $sni }}{{- end }}, {{ $common }}\n {{- else if eq $proxy.Type \"vmess\" }}\n{{ $proxy.Name }} = vmess, {{ $server }}, {{ $proxy.Port }}, username={{ $password }}{{- if or (eq $proxy.Transport \"ws\") (eq $proxy.Transport \"websocket\") }}, ws=true{{- if ne (default \"\" $proxy.Path) \"\" }}, ws-path={{ $proxy.Path }}{{- end }}{{- if ne (default \"\" $proxy.Host) \"\" }}, ws-headers=\"Host:{{ $proxy.Host }}\"{{- end }}{{- else if eq $proxy.Transport \"grpc\" }}, grpc=true{{- if ne (default \"\" $proxy.ServiceName) \"\" }}, grpc-service-name={{ $proxy.ServiceName }}{{- end }}{{- end }}{{- if or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\") }}, tls=true{{- end }}{{- if ne $sni \"\" }}, sni={{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify=true{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}, fingerprint={{ $proxy.Fingerprint }}{{- end }}, {{ $common }}\n {{- else if eq $proxy.Type \"vless\" }}\n{{ $proxy.Name }} = vless, {{ $server }}, {{ $proxy.Port }}, username={{ $password }}{{- if or (eq $proxy.Transport \"ws\") (eq $proxy.Transport \"websocket\") }}, ws=true{{- if ne (default \"\" $proxy.Path) \"\" }}, ws-path={{ $proxy.Path }}{{- end }}{{- if ne (default \"\" $proxy.Host) \"\" }}, ws-headers=\"Host:{{ $proxy.Host }}\"{{- end }}{{- else if eq $proxy.Transport \"grpc\" }}, grpc=true{{- if ne (default \"\" $proxy.ServiceName) \"\" }}, grpc-service-name={{ $proxy.ServiceName }}{{- end }}{{- end }}{{- if ne $sni \"\" }}, sni={{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify=true{{- end }}{{- if ne (default \"\" $proxy.Flow) \"\" }}, flow={{ $proxy.Flow }}{{- end }}, {{ $common }}\n {{- else if eq $proxy.Type \"trojan\" }}\n{{ $proxy.Name }} = trojan, {{ $server }}, {{ $proxy.Port }}, password={{ $password }}{{- if or (eq $proxy.Transport \"ws\") (eq $proxy.Transport \"websocket\") }}, ws=true{{- if ne (default \"\" $proxy.Path) \"\" }}, ws-path={{ $proxy.Path }}{{- end }}{{- if ne (default \"\" $proxy.Host) \"\" }}, ws-headers=\"Host:{{ $proxy.Host }}\"{{- end }}{{- else if eq $proxy.Transport \"grpc\" }}, grpc=true{{- if ne (default \"\" $proxy.ServiceName) \"\" }}, grpc-service-name={{ $proxy.ServiceName }}{{- end }}{{- end }}{{- if ne $sni \"\" }}, sni={{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify=true{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}, fingerprint={{ $proxy.Fingerprint }}{{- end }}, {{ $common }}\n {{- else if or (eq $proxy.Type \"hysteria2\") (eq $proxy.Type \"hy2\") }}\n{{ $proxy.Name }} = hysteria2, {{ $server }}, {{ $proxy.Port }}, password={{ $password }}{{- if ne $sni \"\" }}, sni={{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify=true{{- end }}{{- if ne (default \"\" $proxy.ObfsPassword) \"\" }}, obfs=salamander, obfs-password={{ $proxy.ObfsPassword }}{{- end }}{{- if ne (default \"\" $proxy.HopPorts) \"\" }}, ports={{ $proxy.HopPorts }}{{- end }}{{- if ne (default 0 $proxy.HopInterval) 0 }}, hop-interval={{ $proxy.HopInterval }}{{- end }}, {{ $common }}\n {{- else if eq $proxy.Type \"tuic\" }}\n{{ $proxy.Name }} = tuic, {{ $server }}, {{ $proxy.Port }}, uuid={{ default \"\" $proxy.ServerKey }}, password={{ $password }}{{- if ne $sni \"\" }}, sni={{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify=true{{- end }}{{- if $proxy.DisableSNI }}, disable-sni=true{{- end }}{{- if $proxy.ReduceRtt }}, reduce-rtt=true{{- end }}{{- if ne (default \"\" $proxy.UDPRelayMode) \"\" }}, udp-relay-mode={{ $proxy.UDPRelayMode }}{{- end }}{{- if ne (default \"\" $proxy.CongestionController) \"\" }}, congestion-controller={{ $proxy.CongestionController }}{{- end }}, {{ $common }}\n {{- else if eq $proxy.Type \"wireguard\" }}\n{{ $proxy.Name }} = wireguard, {{ $server }}, {{ $proxy.Port }}, private-key={{ default \"\" $proxy.ServerKey }}, public-key={{ default \"\" $proxy.RealityPublicKey }}{{- if ne (default \"\" $proxy.Path) \"\" }}, preshared-key={{ $proxy.Path }}{{- end }}{{- if ne (default \"\" $proxy.RealityServerAddr) \"\" }}, ip={{ $proxy.RealityServerAddr }}{{- end }}{{- if ne (default 0 $proxy.RealityServerPort) 0 }}, ipv6={{ $proxy.RealityServerPort }}{{- end }}, {{ $common }}\n {{- else if eq $proxy.Type \"anytls\" }}\n{{ $proxy.Name }} = anytls, {{ $server }}, {{ $proxy.Port }}, password={{ $password }}{{- if ne $sni \"\" }}, sni={{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify=true{{- end }}, {{ $common }}\n {{- else }}\n{{ $proxy.Name }} = {{ $proxy.Type }}, {{ $server }}, {{ $proxy.Port }}, {{ $common }}\n {{- end }}\n{{- end }}\n\n[Proxy Group]\n🚀 Proxy = select, 🌏 Auto, 🎯 Direct, include-other-group=🇺🇳 Nodes\n🍎 Apple = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes\n🔍 Google = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes\n🪟 Microsoft = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes\n📺 GlobalMedia = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes\n🤖 AI = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes\n🪙 Crypto = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes\n🎮 Game = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes\n📟 Telegram = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes\n🇨🇳 China = select, 🎯 Direct, 🚀 Proxy, include-other-group=🇺🇳 Nodes\n🐠 Final = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes\n🌏 Auto = smart, include-other-group=🇺🇳 Nodes\n🎯 Direct = select, DIRECT, hidden=1\n🇺🇳 Nodes = select, {{ $proxyNames }}, hidden=1\n\n[Rule]\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Apple/Apple_All.list, 🍎 Apple\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Google/Google.list, 🔍 Google\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/GitHub/GitHub.list, 🪟 Microsoft\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Microsoft/Microsoft.list, 🪟 Microsoft\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/HBO/HBO.list, 📺 GlobalMedia\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Disney/Disney.list, 📺 GlobalMedia\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/TikTok/TikTok.list, 📺 GlobalMedia\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Netflix/Netflix.list, 📺 GlobalMedia\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/GlobalMedia/GlobalMedia_All_No_Resolve.list, 📺 GlobalMedia\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Telegram/Telegram.list, 📟 Telegram\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/OpenAI/OpenAI.list, 🤖 AI\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Gemini/Gemini.list, 🤖 AI\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Copilot/Copilot.list, 🤖 AI\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Claude/Claude.list, 🤖 AI\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Crypto/Crypto.list, 🪙 Crypto\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Cryptocurrency/Cryptocurrency.list, 🪙 Crypto\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Game/Game.list, 🎮 Game\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Global/Global_All_No_Resolve.list, 🚀 Proxy\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/ChinaMax/ChinaMax_All_No_Resolve.list, 🇨🇳 China\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Lan/Lan.list, 🎯 Direct\n\nGEOIP, CN, 🇨🇳 China\nFINAL, 🐠 Final, dns-failed\n\n[URL Rewrite]\n^https?:\\/\\/(www.)?g\\.cn https://www.google.com 302\n^https?:\\/\\/(www.)?google\\.cn https://www.google.com 302\n\n{{- range $proxy := $supportedProxies }}\n {{- if not (or (eq $proxy.Type \"shadowsocks\") (eq $proxy.Type \"vmess\") (eq $proxy.Type \"trojan\") (eq $proxy.Type \"hysteria2\") (eq $proxy.Type \"tuic\")) }}\n# Skipped (unsupported by Surge): {{ $proxy.Name }} ({{ $proxy.Type }})\n {{- end }}\n{{- end }}', 'conf', '{}', '2025-08-13 00:12:37.809', '2025-08-15 22:00:50.528'); COMMIT; diff --git a/initialize/migrate/database/02102_subscribe_config.down.sql b/initialize/migrate/database/02102_subscribe_config.down.sql new file mode 100644 index 0000000..e69de29 diff --git a/initialize/migrate/database/02102_subscribe_config.up.sql b/initialize/migrate/database/02102_subscribe_config.up.sql new file mode 100644 index 0000000..4460100 --- /dev/null +++ b/initialize/migrate/database/02102_subscribe_config.up.sql @@ -0,0 +1,4 @@ +INSERT IGNORE INTO `system` (`id`, `category`, `key`, `value`, `type`, `desc`, `created_at`, `updated_at`) +VALUES + (42, 'subscribe', 'UserAgentLimit', 'false', 'bool', 'User Agent Limit', '2025-04-22 14:25:16.637', '2025-04-22 14:25:16.637'), + (43, 'subscribe', 'UserAgentList', '', 'string', 'User Agent List', '2025-04-22 14:25:16.637','2025-04-22 14:25:16.637'); \ No newline at end of file diff --git a/initialize/migrate/database/02103_delete_application.down.sql b/initialize/migrate/database/02103_delete_application.down.sql new file mode 100644 index 0000000..e69de29 diff --git a/initialize/migrate/database/02103_delete_application.up.sql b/initialize/migrate/database/02103_delete_application.up.sql new file mode 100644 index 0000000..1a3a778 --- /dev/null +++ b/initialize/migrate/database/02103_delete_application.up.sql @@ -0,0 +1,3 @@ +DROP TABLE IF EXISTS `application`; +DROP TABLE IF EXISTS `application_version`; +DROP TABLE IF EXISTS `application_config`; \ No newline at end of file diff --git a/initialize/migrate/database/02104_system_log.down.sql b/initialize/migrate/database/02104_system_log.down.sql new file mode 100644 index 0000000..2682c97 --- /dev/null +++ b/initialize/migrate/database/02104_system_log.down.sql @@ -0,0 +1,106 @@ +CREATE TABLE IF NOT EXISTS `user_balance_log` +( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint NOT NULL COMMENT 'User ID', + `amount` bigint NOT NULL COMMENT 'Amount', + `type` tinyint(1) NOT NULL COMMENT 'Type: 1: Recharge 2: Withdraw 3: Payment 4: Refund 5: Reward', + `order_id` bigint DEFAULT NULL COMMENT 'Order ID', + `balance` bigint NOT NULL COMMENT 'Balance', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Creation Time', + PRIMARY KEY (`id`), + KEY `idx_user_id` (`user_id`) + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_general_ci; + +CREATE TABLE IF NOT EXISTS `user_commission_log` +( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint NOT NULL COMMENT 'User ID', + `order_no` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'Order No.', + `amount` bigint NOT NULL COMMENT 'Amount', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Creation Time', + PRIMARY KEY (`id`), + KEY `idx_user_id` (`user_id`) + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_general_ci; + +CREATE TABLE IF NOT EXISTS `user_gift_amount_log` +( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint NOT NULL COMMENT 'User ID', + `user_subscribe_id` bigint DEFAULT NULL COMMENT 'Deduction User Subscribe ID', + `order_no` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'Order No.', + `type` tinyint(1) NOT NULL COMMENT 'Type: 1: Increase 2: Reduce', + `amount` bigint NOT NULL COMMENT 'Amount', + `balance` bigint NOT NULL COMMENT 'Balance', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'Remark', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Creation Time', + PRIMARY KEY (`id`), + KEY `idx_user_id` (`user_id`) + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_general_ci; + +CREATE TABLE IF NOT EXISTS `user_login_log` +( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint NOT NULL COMMENT 'User ID', + `login_ip` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Login IP', + `user_agent` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'UserAgent', + `success` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Login Success', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Creation Time', + PRIMARY KEY (`id`), + KEY `idx_user_id` (`user_id`) + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_general_ci; + +CREATE TABLE IF NOT EXISTS `user_reset_subscribe_log` +( + `id` BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + `user_id` BIGINT NOT NULL COMMENT 'User ID', + `type` TINYINT(1) NOT NULL COMMENT 'Type: 1: Auto 2: Advance 3: Paid', + `order_no` VARCHAR(255) DEFAULT NULL COMMENT 'Order No.', + `user_subscribe_id` BIGINT NOT NULL COMMENT 'User Subscribe ID', + `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Creation Time', + INDEX `idx_user_id` (`user_id`), + INDEX `idx_user_subscribe_id` (`user_subscribe_id`) + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_general_ci; + +CREATE TABLE IF NOT EXISTS `user_subscribe_log` +( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint NOT NULL COMMENT 'User ID', + `user_subscribe_id` bigint NOT NULL COMMENT 'User Subscribe ID', + `token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Token', + `ip` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'IP', + `user_agent` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'UserAgent', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Creation Time', + PRIMARY KEY (`id`), + KEY `idx_user_id` (`user_id`), + KEY `idx_user_subscribe_id` (`user_subscribe_id`) + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_general_ci; + +CREATE TABLE IF NOT EXISTS `message_log` +( + `id` bigint NOT NULL AUTO_INCREMENT, + `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'email' COMMENT 'Message Type', + `platform` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'smtp' COMMENT 'Platform', + `to` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'To', + `subject` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Subject', + `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'Content', + `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Status', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Create Time', + `updated_at` datetime(3) DEFAULT NULL COMMENT 'Update Time', + PRIMARY KEY (`id`) + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_general_ci; + +DROP TABLE IF EXISTS `system_logs`; \ No newline at end of file diff --git a/initialize/migrate/database/02104_system_log.up.sql b/initialize/migrate/database/02104_system_log.up.sql new file mode 100644 index 0000000..b518e68 --- /dev/null +++ b/initialize/migrate/database/02104_system_log.up.sql @@ -0,0 +1,19 @@ +DROP TABLE IF EXISTS `user_balance_log`; +DROP TABLE IF EXISTS `user_commission_log`; +DROP TABLE IF EXISTS `user_gift_amount_log`; +DROP TABLE IF EXISTS `user_login_log`; +DROP TABLE IF EXISTS `user_reset_subscribe_log`; +DROP TABLE IF EXISTS `user_subscribe_log`; +DROP TABLE IF EXISTS `message_log`; +DROP TABLE IF EXISTS `system_logs`; +CREATE TABLE `system_logs` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `type` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Log Type: 1: Email Message 2: Mobile Message 3: Subscribe 4: Subscribe Traffic 5: Server Traffic 6: Login 7: Register 8: Balance 9: Commission 10: Reset Subscribe 11: Gift', + `date` varchar(20) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'Log Date', + `object_id` bigint NOT NULL DEFAULT '0' COMMENT 'Object ID', + `content` text COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Log Content', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Create Time', + PRIMARY KEY (`id`), + KEY `idx_type` (`type`), + KEY `idx_object_id` (`object_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; \ No newline at end of file diff --git a/initialize/migrate/database/02105_node.down.sql b/initialize/migrate/database/02105_node.down.sql new file mode 100644 index 0000000..210462e --- /dev/null +++ b/initialize/migrate/database/02105_node.down.sql @@ -0,0 +1,2 @@ +DROP TABLE IF EXISTS `nodes`; +DROP TABLE IF EXISTS `servers`; diff --git a/initialize/migrate/database/02105_node.up.sql b/initialize/migrate/database/02105_node.up.sql new file mode 100644 index 0000000..c9c310b --- /dev/null +++ b/initialize/migrate/database/02105_node.up.sql @@ -0,0 +1,28 @@ +CREATE TABLE IF NOT EXISTS `servers` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `name` varchar(100) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Server Name', + `country` varchar(128) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Country', + `city` varchar(128) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'City', + `ratio` decimal(4,2) NOT NULL DEFAULT '0.00' COMMENT 'Traffic Ratio', + `address` varchar(100) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Server Address', + `sort` bigint NOT NULL DEFAULT '0' COMMENT 'Sort', + `protocols` text COLLATE utf8mb4_general_ci COMMENT 'Protocol', + `last_reported_at` datetime(3) DEFAULT NULL COMMENT 'Last Reported Time', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Creation Time', + `updated_at` datetime(3) DEFAULT NULL COMMENT 'Update Time', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +CREATE TABLE IF NOT EXISTS `nodes` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `name` varchar(100) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Node Name', + `tags` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Tags', + `port` smallint unsigned NOT NULL DEFAULT '0' COMMENT 'Connect Port', + `address` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Connect Address', + `server_id` bigint NOT NULL DEFAULT '0' COMMENT 'Server ID', + `protocol` varchar(100) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Protocol', + `enabled` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'Enabled', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Creation Time', + `updated_at` datetime(3) DEFAULT NULL COMMENT 'Update Time', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; diff --git a/initialize/migrate/database/02106_subscribe.down.sql b/initialize/migrate/database/02106_subscribe.down.sql new file mode 100644 index 0000000..20984b7 --- /dev/null +++ b/initialize/migrate/database/02106_subscribe.down.sql @@ -0,0 +1,5 @@ +ALTER TABLE `subscribe` +DROP COLUMN `nodes`, + DROP COLUMN `node_tags`, + ADD COLUMN `server` VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'Server', + ADD COLUMN `server_group` VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'Server Group'; diff --git a/initialize/migrate/database/02106_subscribe.up.sql b/initialize/migrate/database/02106_subscribe.up.sql new file mode 100644 index 0000000..28f5db5 --- /dev/null +++ b/initialize/migrate/database/02106_subscribe.up.sql @@ -0,0 +1,7 @@ +ALTER TABLE `subscribe` +ADD COLUMN `nodes` VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'Node IDs', +ADD COLUMN `node_tags` VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'Node Tags', +DROP COLUMN `server`, +DROP COLUMN `server_group`; + +DROP TABLE IF EXISTS `server_rule_group`; diff --git a/initialize/migrate/database/02107_log_setting.down.sql b/initialize/migrate/database/02107_log_setting.down.sql new file mode 100644 index 0000000..e69de29 diff --git a/initialize/migrate/database/02107_log_setting.up.sql b/initialize/migrate/database/02107_log_setting.up.sql new file mode 100644 index 0000000..c1bc8e2 --- /dev/null +++ b/initialize/migrate/database/02107_log_setting.up.sql @@ -0,0 +1,4 @@ +INSERT IGNORE INTO `system` (`category`, `key`, `value`, `type`, `desc`, `created_at`, `updated_at`) +VALUES + ('log', 'AutoClear', 'true', 'bool', 'Auto Clear Log', '2025-04-22 14:25:16.637', '2025-04-22 14:25:16.637'), + ('log', 'ClearDays', '7', 'int', 'Clear Days', '2025-04-22 14:25:16.637','2025-04-22 14:25:16.637'); \ No newline at end of file diff --git a/initialize/migrate/database/02108_user_referral.down.sql b/initialize/migrate/database/02108_user_referral.down.sql new file mode 100644 index 0000000..3bdac5b --- /dev/null +++ b/initialize/migrate/database/02108_user_referral.down.sql @@ -0,0 +1,3 @@ +ALTER TABLE `user` +DROP COLUMN `referral_percentage`, +DROP COLUMN `only_first_purchase`; \ No newline at end of file diff --git a/initialize/migrate/database/02108_user_referral.up.sql b/initialize/migrate/database/02108_user_referral.up.sql new file mode 100644 index 0000000..e50f765 --- /dev/null +++ b/initialize/migrate/database/02108_user_referral.up.sql @@ -0,0 +1,7 @@ +ALTER TABLE `user` + ADD COLUMN `referral_percentage` TINYINT UNSIGNED NOT NULL DEFAULT 0 + COMMENT 'Referral Percentage' + AFTER `commission`, + ADD COLUMN `only_first_purchase` TINYINT(1) NOT NULL DEFAULT 1 + COMMENT 'Only First Purchase' + AFTER `referral_percentage`; diff --git a/initialize/migrate/database/02109_node_sort.down.sql b/initialize/migrate/database/02109_node_sort.down.sql new file mode 100644 index 0000000..4413646 --- /dev/null +++ b/initialize/migrate/database/02109_node_sort.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE `nodes` +DROP COLUMN `sort`; \ No newline at end of file diff --git a/initialize/migrate/database/02109_node_sort.up.sql b/initialize/migrate/database/02109_node_sort.up.sql new file mode 100644 index 0000000..1a993d0 --- /dev/null +++ b/initialize/migrate/database/02109_node_sort.up.sql @@ -0,0 +1,3 @@ +ALTER TABLE `nodes` + ADD COLUMN `sort` INT UNSIGNED NOT NULL DEFAULT 0 + COMMENT 'Sort' AFTER `enabled`; \ No newline at end of file diff --git a/initialize/migrate/database/02110_traffic_log_index.down.sql b/initialize/migrate/database/02110_traffic_log_index.down.sql new file mode 100644 index 0000000..f42807c --- /dev/null +++ b/initialize/migrate/database/02110_traffic_log_index.down.sql @@ -0,0 +1 @@ +DROP INDEX idx_traffic_log_time_user_sub ON traffic_log; diff --git a/initialize/migrate/database/02110_traffic_log_index.up.sql b/initialize/migrate/database/02110_traffic_log_index.up.sql new file mode 100644 index 0000000..2cf61f2 --- /dev/null +++ b/initialize/migrate/database/02110_traffic_log_index.up.sql @@ -0,0 +1 @@ +CREATE INDEX idx_traffic_log_time_user_sub ON traffic_log (timestamp, user_id, subscribe_id); diff --git a/initialize/migrate/database/02111_clear_table.down.sql b/initialize/migrate/database/02111_clear_table.down.sql new file mode 100644 index 0000000..85c9f3f --- /dev/null +++ b/initialize/migrate/database/02111_clear_table.down.sql @@ -0,0 +1,2 @@ +DROP TABLE IF EXISTS `subscribe_type`; +DROP TABLE IF EXISTS `sms`; \ No newline at end of file diff --git a/initialize/migrate/database/02111_clear_table.up.sql b/initialize/migrate/database/02111_clear_table.up.sql new file mode 100644 index 0000000..85c9f3f --- /dev/null +++ b/initialize/migrate/database/02111_clear_table.up.sql @@ -0,0 +1,2 @@ +DROP TABLE IF EXISTS `subscribe_type`; +DROP TABLE IF EXISTS `sms`; \ No newline at end of file diff --git a/initialize/migrate/database/02112_subscribe.down.sql b/initialize/migrate/database/02112_subscribe.down.sql new file mode 100644 index 0000000..e69de29 diff --git a/initialize/migrate/database/02112_subscribe.up.sql b/initialize/migrate/database/02112_subscribe.up.sql new file mode 100644 index 0000000..1a79dbc --- /dev/null +++ b/initialize/migrate/database/02112_subscribe.up.sql @@ -0,0 +1,7 @@ +ALTER TABLE `subscribe` +DROP COLUMN `group_id`, +ADD COLUMN `language` VARCHAR(255) NOT NULL DEFAULT '' + COMMENT 'Language' + AFTER `name`; + +DROP TABLE IF EXISTS `subscribe_group`; \ No newline at end of file diff --git a/initialize/migrate/database/02113_task.down.sql b/initialize/migrate/database/02113_task.down.sql new file mode 100644 index 0000000..e69de29 diff --git a/initialize/migrate/database/02113_task.up.sql b/initialize/migrate/database/02113_task.up.sql new file mode 100644 index 0000000..4e7b170 --- /dev/null +++ b/initialize/migrate/database/02113_task.up.sql @@ -0,0 +1,14 @@ +DROP TABLE IF EXISTS `email_task`; +CREATE TABLE `task` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID', + `type` tinyint NOT NULL COMMENT 'Task Type', + `scope` text COLLATE utf8mb4_general_ci COMMENT 'Task Scope', + `content` text COLLATE utf8mb4_general_ci COMMENT 'Task Content', + `status` tinyint NOT NULL DEFAULT '0' COMMENT 'Task Status: 0: Pending, 1: In Progress, 2: Completed, 3: Failed', + `errors` text COLLATE utf8mb4_general_ci COMMENT 'Task Errors', + `total` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'Total Number', + `current` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'Current Number', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Creation Time', + `updated_at` datetime(3) DEFAULT NULL COMMENT 'Update Time', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; \ No newline at end of file diff --git a/initialize/migrate/migrate_test.go b/initialize/migrate/migrate_test.go index c22e52b..531266e 100644 --- a/initialize/migrate/migrate_test.go +++ b/initialize/migrate/migrate_test.go @@ -3,7 +3,10 @@ package migrate import ( "testing" + "github.com/perfect-panel/server/internal/model/node" "github.com/perfect-panel/server/pkg/orm" + "gorm.io/driver/mysql" + "gorm.io/gorm" ) func getDSN() string { @@ -30,3 +33,17 @@ func TestMigrate(t *testing.T) { t.Log("migrate success") } } +func TestMysql(t *testing.T) { + db, err := gorm.Open(mysql.New(mysql.Config{ + DSN: "root:mylove520@tcp(localhost:3306)/vpnboard", + })) + if err != nil { + t.Fatalf("Failed to connect to MySQL: %v", err) + } + err = db.Migrator().AutoMigrate(&node.Node{}) + if err != nil { + t.Fatalf("Failed to auto migrate: %v", err) + return + } + t.Log("MySQL connection and migration successful") +} diff --git a/initialize/statistics.go b/initialize/statistics.go deleted file mode 100644 index 7ab02ad..0000000 --- a/initialize/statistics.go +++ /dev/null @@ -1,57 +0,0 @@ -package initialize - -import ( - "context" - "time" - - "github.com/perfect-panel/server/internal/model/cache" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/logger" -) - -func TrafficDataToRedis(svcCtx *svc.ServiceContext) { - ctx := context.Background() - // 统计昨天的节点流量数据排行榜前10 - nodeData, err := svcCtx.TrafficLogModel.TopServersTrafficByDay(ctx, time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day()-1, 0, 0, 0, 0, time.Local), 10) - if err != nil { - logger.Errorw("统计昨天的流量数据失败", logger.Field("error", err.Error())) - } - var nodeCacheData []cache.NodeTodayTrafficRank - for _, node := range nodeData { - serverInfo, err := svcCtx.ServerModel.FindOne(ctx, node.ServerId) - if err != nil { - logger.Errorw("查询节点信息失败", logger.Field("error", err.Error())) - continue - } - nodeCacheData = append(nodeCacheData, cache.NodeTodayTrafficRank{ - ID: node.ServerId, - Name: serverInfo.Name, - Upload: node.Upload, - Download: node.Download, - Total: node.Upload + node.Download, - }) - } - // 写入缓存 - if err = svcCtx.NodeCache.UpdateYesterdayNodeTotalTrafficRank(ctx, nodeCacheData); err != nil { - logger.Errorw("写入昨天的流量数据到缓存失败", logger.Field("error", err.Error())) - } - // 统计昨天的用户流量数据排行榜前10 - userData, err := svcCtx.TrafficLogModel.TopUsersTrafficByDay(ctx, time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day()-1, 0, 0, 0, 0, time.Local), 10) - if err != nil { - logger.Errorw("统计昨天的流量数据失败", logger.Field("error", err.Error())) - } - var userCacheData []cache.UserTodayTrafficRank - for _, user := range userData { - userCacheData = append(userCacheData, cache.UserTodayTrafficRank{ - SID: user.SubscribeId, - Upload: user.Upload, - Download: user.Download, - Total: user.Upload + user.Download, - }) - } - // 写入缓存 - if err = svcCtx.NodeCache.UpdateYesterdayUserTotalTrafficRank(ctx, userCacheData); err != nil { - logger.Errorw("写入昨天的流量数据到缓存失败", logger.Field("error", err.Error())) - } - logger.Infow("初始化昨天的流量数据到缓存成功") -} diff --git a/internal/config/cacheKey.go b/internal/config/cacheKey.go index 02f5be9..655ce55 100644 --- a/internal/config/cacheKey.go +++ b/internal/config/cacheKey.go @@ -12,9 +12,6 @@ const SiteConfigKey = "system:site_config" // SubscribeConfigKey Subscribe Config Key const SubscribeConfigKey = "system:subscribe_config" -// ApplicationKey Application Key -const ApplicationKey = "system:application" - // RegisterConfigKey Register Config Key const RegisterConfigKey = "system:register_config" @@ -51,26 +48,12 @@ const AuthCodeCacheKey = "auth:verify:email" // AuthCodeTelephoneCacheKey Register Code Cache Key const AuthCodeTelephoneCacheKey = "auth:verify:telephone" -// ServerUserListCacheKey Server User List Cache Key -const ServerUserListCacheKey = "server:user_list:id:" - -// ServerConfigCacheKey Server Config Cache Key -const ServerConfigCacheKey = "server:config:id:" - -// CommonStat Cache Key +// CommonStatCacheKey CommonStat Cache Key const CommonStatCacheKey = "common:stat" -// ServerStatusCacheKey Server Status Cache Key -const ServerStatusCacheKey = "server:status:id:" - // ServerCountCacheKey Server Count Cache Key const ServerCountCacheKey = "server:count" -// UserBindTelegramCacheKey User Bind Telegram Cache Key -const UserBindTelegramCacheKey = "user:bind:telegram:code:" - -const CacheSmsCount = "cache:sms:count" - // SendIntervalKeyPrefix Auth Code Send Interval Key Prefix const SendIntervalKeyPrefix = "send:interval:" diff --git a/internal/config/config.go b/internal/config/config.go index 1d51df4..9065bcb 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -25,6 +25,7 @@ type Config struct { Subscribe SubscribeConfig `yaml:"Subscribe"` Invite InviteConfig `yaml:"Invite"` Telegram Telegram `yaml:"Telegram"` + Log Log `yaml:"Log"` Administrator struct { Email string `yaml:"Email" default:"admin@ppanel.dev"` Password string `yaml:"Password" default:"password"` @@ -55,6 +56,8 @@ type SubscribeConfig struct { SubscribePath string `yaml:"SubscribePath" default:"/api/subscribe"` SubscribeDomain string `yaml:"SubscribeDomain" default:""` PanDomain bool `yaml:"PanDomain" default:"false"` + UserAgentLimit bool `yaml:"UserAgentLimit" default:"false"` + UserAgentList string `yaml:"UserAgentList" default:""` } type RegisterConfig struct { @@ -144,3 +147,8 @@ type VerifyCode struct { Limit int64 `yaml:"Limit" default:"15"` Interval int64 `yaml:"Interval" default:"60"` } + +type Log struct { + AutoClear bool `yaml:"AutoClear" default:"true"` + ClearDays int64 `yaml:"ClearDays" default:"7"` +} diff --git a/internal/handler/app/order/queryorderdetailhandler.go b/internal/handler/admin/log/filterBalanceLogHandler.go similarity index 58% rename from internal/handler/app/order/queryorderdetailhandler.go rename to internal/handler/admin/log/filterBalanceLogHandler.go index bb8a109..c8bf7d1 100644 --- a/internal/handler/app/order/queryorderdetailhandler.go +++ b/internal/handler/admin/log/filterBalanceLogHandler.go @@ -1,17 +1,17 @@ -package order +package log import ( "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/order" + "github.com/perfect-panel/server/internal/logic/admin/log" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/result" ) -// Get order -func QueryOrderDetailHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { +// Filter balance log +func FilterBalanceLogHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { - var req types.QueryOrderDetailRequest + var req types.FilterBalanceLogRequest _ = c.ShouldBind(&req) validateErr := svcCtx.Validate(&req) if validateErr != nil { @@ -19,8 +19,8 @@ func QueryOrderDetailHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return } - l := order.NewQueryOrderDetailLogic(c.Request.Context(), svcCtx) - resp, err := l.QueryOrderDetail(&req) + l := log.NewFilterBalanceLogLogic(c.Request.Context(), svcCtx) + resp, err := l.FilterBalanceLog(&req) result.HttpResult(c, resp, err) } } diff --git a/internal/handler/app/document/querydocumentdetailhandler.go b/internal/handler/admin/log/filterCommissionLogHandler.go similarity index 56% rename from internal/handler/app/document/querydocumentdetailhandler.go rename to internal/handler/admin/log/filterCommissionLogHandler.go index 7b0063d..07361cd 100644 --- a/internal/handler/app/document/querydocumentdetailhandler.go +++ b/internal/handler/admin/log/filterCommissionLogHandler.go @@ -1,17 +1,17 @@ -package document +package log import ( "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/document" + "github.com/perfect-panel/server/internal/logic/admin/log" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/result" ) -// Get document detail -func QueryDocumentDetailHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { +// Filter commission log +func FilterCommissionLogHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { - var req types.QueryDocumentDetailRequest + var req types.FilterCommissionLogRequest _ = c.ShouldBind(&req) validateErr := svcCtx.Validate(&req) if validateErr != nil { @@ -19,8 +19,8 @@ func QueryDocumentDetailHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) return } - l := document.NewQueryDocumentDetailLogic(c.Request.Context(), svcCtx) - resp, err := l.QueryDocumentDetail(&req) + l := log.NewFilterCommissionLogLogic(c.Request.Context(), svcCtx) + resp, err := l.FilterCommissionLog(&req) result.HttpResult(c, resp, err) } } diff --git a/internal/handler/app/order/queryorderlisthandler.go b/internal/handler/admin/log/filterEmailLogHandler.go similarity index 58% rename from internal/handler/app/order/queryorderlisthandler.go rename to internal/handler/admin/log/filterEmailLogHandler.go index 98e8575..6d9f03d 100644 --- a/internal/handler/app/order/queryorderlisthandler.go +++ b/internal/handler/admin/log/filterEmailLogHandler.go @@ -1,17 +1,17 @@ -package order +package log import ( "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/order" + "github.com/perfect-panel/server/internal/logic/admin/log" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/result" ) -// Get order list -func QueryOrderListHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { +// Filter email log +func FilterEmailLogHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { - var req types.QueryOrderListRequest + var req types.FilterLogParams _ = c.ShouldBind(&req) validateErr := svcCtx.Validate(&req) if validateErr != nil { @@ -19,8 +19,8 @@ func QueryOrderListHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return } - l := order.NewQueryOrderListLogic(c.Request.Context(), svcCtx) - resp, err := l.QueryOrderList(&req) + l := log.NewFilterEmailLogLogic(c.Request.Context(), svcCtx) + resp, err := l.FilterEmailLog(&req) result.HttpResult(c, resp, err) } } diff --git a/internal/handler/app/order/checkoutorderhandler.go b/internal/handler/admin/log/filterGiftLogHandler.go similarity index 57% rename from internal/handler/app/order/checkoutorderhandler.go rename to internal/handler/admin/log/filterGiftLogHandler.go index 6b16b39..e650a27 100644 --- a/internal/handler/app/order/checkoutorderhandler.go +++ b/internal/handler/admin/log/filterGiftLogHandler.go @@ -1,17 +1,17 @@ -package order +package log import ( "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/order" + "github.com/perfect-panel/server/internal/logic/admin/log" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/result" ) -// Checkout order -func CheckoutOrderHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { +// Filter gift log +func FilterGiftLogHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { - var req types.CheckoutOrderRequest + var req types.FilterGiftLogRequest _ = c.ShouldBind(&req) validateErr := svcCtx.Validate(&req) if validateErr != nil { @@ -19,8 +19,8 @@ func CheckoutOrderHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return } - l := order.NewCheckoutOrderLogic(c.Request.Context(), svcCtx) - resp, err := l.CheckoutOrder(&req, c.Request.Host) + l := log.NewFilterGiftLogLogic(c.Request.Context(), svcCtx) + resp, err := l.FilterGiftLog(&req) result.HttpResult(c, resp, err) } } diff --git a/internal/handler/app/order/precreateorderhandler.go b/internal/handler/admin/log/filterLoginLogHandler.go similarity index 58% rename from internal/handler/app/order/precreateorderhandler.go rename to internal/handler/admin/log/filterLoginLogHandler.go index 53b19a1..c2dae41 100644 --- a/internal/handler/app/order/precreateorderhandler.go +++ b/internal/handler/admin/log/filterLoginLogHandler.go @@ -1,17 +1,17 @@ -package order +package log import ( "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/order" + "github.com/perfect-panel/server/internal/logic/admin/log" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/result" ) -// Pre create order -func PreCreateOrderHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { +// Filter login log +func FilterLoginLogHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { - var req types.PurchaseOrderRequest + var req types.FilterLoginLogRequest _ = c.ShouldBind(&req) validateErr := svcCtx.Validate(&req) if validateErr != nil { @@ -19,8 +19,8 @@ func PreCreateOrderHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return } - l := order.NewPreCreateOrderLogic(c.Request.Context(), svcCtx) - resp, err := l.PreCreateOrder(&req) + l := log.NewFilterLoginLogLogic(c.Request.Context(), svcCtx) + resp, err := l.FilterLoginLog(&req) result.HttpResult(c, resp, err) } } diff --git a/internal/handler/app/node/getNodeListHandler.go b/internal/handler/admin/log/filterMobileLogHandler.go similarity index 56% rename from internal/handler/app/node/getNodeListHandler.go rename to internal/handler/admin/log/filterMobileLogHandler.go index 4363e35..0d45e27 100644 --- a/internal/handler/app/node/getNodeListHandler.go +++ b/internal/handler/admin/log/filterMobileLogHandler.go @@ -1,17 +1,17 @@ -package node +package log import ( "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/node" + "github.com/perfect-panel/server/internal/logic/admin/log" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/result" ) -// Get Node list -func GetNodeListHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { +// Filter mobile log +func FilterMobileLogHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { - var req types.AppUserSubscbribeNodeRequest + var req types.FilterLogParams _ = c.ShouldBind(&req) validateErr := svcCtx.Validate(&req) if validateErr != nil { @@ -19,8 +19,8 @@ func GetNodeListHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return } - l := node.NewGetNodeListLogic(c.Request.Context(), svcCtx) - resp, err := l.GetNodeList(&req) + l := log.NewFilterMobileLogLogic(c.Request.Context(), svcCtx) + resp, err := l.FilterMobileLog(&req) result.HttpResult(c, resp, err) } } diff --git a/internal/handler/app/announcement/queryannouncementhandler.go b/internal/handler/admin/log/filterRegisterLogHandler.go similarity index 55% rename from internal/handler/app/announcement/queryannouncementhandler.go rename to internal/handler/admin/log/filterRegisterLogHandler.go index 327ab1e..a5ca9e8 100644 --- a/internal/handler/app/announcement/queryannouncementhandler.go +++ b/internal/handler/admin/log/filterRegisterLogHandler.go @@ -1,17 +1,17 @@ -package announcement +package log import ( "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/announcement" + "github.com/perfect-panel/server/internal/logic/admin/log" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/result" ) -// Query announcement -func QueryAnnouncementHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { +// Filter register log +func FilterRegisterLogHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { - var req types.QueryAnnouncementRequest + var req types.FilterRegisterLogRequest _ = c.ShouldBind(&req) validateErr := svcCtx.Validate(&req) if validateErr != nil { @@ -19,8 +19,8 @@ func QueryAnnouncementHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return } - l := announcement.NewQueryAnnouncementLogic(c.Request.Context(), svcCtx) - resp, err := l.QueryAnnouncement(&req) + l := log.NewFilterRegisterLogLogic(c.Request.Context(), svcCtx) + resp, err := l.FilterRegisterLog(&req) result.HttpResult(c, resp, err) } } diff --git a/internal/handler/admin/log/filterResetSubscribeLogHandler.go b/internal/handler/admin/log/filterResetSubscribeLogHandler.go new file mode 100644 index 0000000..f4d96e5 --- /dev/null +++ b/internal/handler/admin/log/filterResetSubscribeLogHandler.go @@ -0,0 +1,26 @@ +package log + +import ( + "github.com/gin-gonic/gin" + "github.com/perfect-panel/server/internal/logic/admin/log" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/result" +) + +// Filter reset subscribe log +func FilterResetSubscribeLogHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { + return func(c *gin.Context) { + var req types.FilterResetSubscribeLogRequest + _ = c.ShouldBind(&req) + validateErr := svcCtx.Validate(&req) + if validateErr != nil { + result.ParamErrorResult(c, validateErr) + return + } + + l := log.NewFilterResetSubscribeLogLogic(c.Request.Context(), svcCtx) + resp, err := l.FilterResetSubscribeLog(&req) + result.HttpResult(c, resp, err) + } +} diff --git a/internal/handler/app/user/queryuseraffiliatelisthandler.go b/internal/handler/admin/log/filterServerTrafficLogHandler.go similarity index 56% rename from internal/handler/app/user/queryuseraffiliatelisthandler.go rename to internal/handler/admin/log/filterServerTrafficLogHandler.go index 3368cbd..ec522ed 100644 --- a/internal/handler/app/user/queryuseraffiliatelisthandler.go +++ b/internal/handler/admin/log/filterServerTrafficLogHandler.go @@ -1,17 +1,17 @@ -package user +package log import ( "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/user" + "github.com/perfect-panel/server/internal/logic/admin/log" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/result" ) -// Query User Affiliate List -func QueryUserAffiliateListHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { +// Filter server traffic log +func FilterServerTrafficLogHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { - var req types.QueryUserAffiliateListRequest + var req types.FilterServerTrafficLogRequest _ = c.ShouldBind(&req) validateErr := svcCtx.Validate(&req) if validateErr != nil { @@ -19,8 +19,8 @@ func QueryUserAffiliateListHandler(svcCtx *svc.ServiceContext) func(c *gin.Conte return } - l := user.NewQueryUserAffiliateListLogic(c.Request.Context(), svcCtx) - resp, err := l.QueryUserAffiliateList(&req) + l := log.NewFilterServerTrafficLogLogic(c.Request.Context(), svcCtx) + resp, err := l.FilterServerTrafficLog(&req) result.HttpResult(c, resp, err) } } diff --git a/internal/handler/app/auth/getAppConfigHandler.go b/internal/handler/admin/log/filterSubscribeLogHandler.go similarity index 55% rename from internal/handler/app/auth/getAppConfigHandler.go rename to internal/handler/admin/log/filterSubscribeLogHandler.go index 088525b..f01b61e 100644 --- a/internal/handler/app/auth/getAppConfigHandler.go +++ b/internal/handler/admin/log/filterSubscribeLogHandler.go @@ -1,17 +1,17 @@ -package auth +package log import ( "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/auth" + "github.com/perfect-panel/server/internal/logic/admin/log" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/result" ) -// GetAppConfig -func GetAppConfigHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { +// Filter subscribe log +func FilterSubscribeLogHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { - var req types.AppConfigRequest + var req types.FilterSubscribeLogRequest _ = c.ShouldBind(&req) validateErr := svcCtx.Validate(&req) if validateErr != nil { @@ -19,8 +19,8 @@ func GetAppConfigHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return } - l := auth.NewGetAppConfigLogic(c, svcCtx) - resp, err := l.GetAppConfig(&req) + l := log.NewFilterSubscribeLogLogic(c.Request.Context(), svcCtx) + resp, err := l.FilterSubscribeLog(&req) result.HttpResult(c, resp, err) } } diff --git a/internal/handler/admin/log/filterTrafficLogDetailsHandler.go b/internal/handler/admin/log/filterTrafficLogDetailsHandler.go new file mode 100644 index 0000000..c77a881 --- /dev/null +++ b/internal/handler/admin/log/filterTrafficLogDetailsHandler.go @@ -0,0 +1,26 @@ +package log + +import ( + "github.com/gin-gonic/gin" + "github.com/perfect-panel/server/internal/logic/admin/log" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/result" +) + +// Filter traffic log details +func FilterTrafficLogDetailsHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { + return func(c *gin.Context) { + var req types.FilterTrafficLogDetailsRequest + _ = c.ShouldBind(&req) + validateErr := svcCtx.Validate(&req) + if validateErr != nil { + result.ParamErrorResult(c, validateErr) + return + } + + l := log.NewFilterTrafficLogDetailsLogic(c.Request.Context(), svcCtx) + resp, err := l.FilterTrafficLogDetails(&req) + result.HttpResult(c, resp, err) + } +} diff --git a/internal/handler/admin/log/filterUserSubscribeTrafficLogHandler.go b/internal/handler/admin/log/filterUserSubscribeTrafficLogHandler.go new file mode 100644 index 0000000..976e278 --- /dev/null +++ b/internal/handler/admin/log/filterUserSubscribeTrafficLogHandler.go @@ -0,0 +1,26 @@ +package log + +import ( + "github.com/gin-gonic/gin" + "github.com/perfect-panel/server/internal/logic/admin/log" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/result" +) + +// Filter user subscribe traffic log +func FilterUserSubscribeTrafficLogHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { + return func(c *gin.Context) { + var req types.FilterSubscribeTrafficRequest + _ = c.ShouldBind(&req) + validateErr := svcCtx.Validate(&req) + if validateErr != nil { + result.ParamErrorResult(c, validateErr) + return + } + + l := log.NewFilterUserSubscribeTrafficLogLogic(c.Request.Context(), svcCtx) + resp, err := l.FilterUserSubscribeTrafficLog(&req) + result.HttpResult(c, resp, err) + } +} diff --git a/internal/handler/admin/log/getLogSettingHandler.go b/internal/handler/admin/log/getLogSettingHandler.go new file mode 100644 index 0000000..50217cb --- /dev/null +++ b/internal/handler/admin/log/getLogSettingHandler.go @@ -0,0 +1,18 @@ +package log + +import ( + "github.com/gin-gonic/gin" + "github.com/perfect-panel/server/internal/logic/admin/log" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/pkg/result" +) + +// Get log setting +func GetLogSettingHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { + return func(c *gin.Context) { + + l := log.NewGetLogSettingLogic(c.Request.Context(), svcCtx) + resp, err := l.GetLogSetting() + result.HttpResult(c, resp, err) + } +} diff --git a/internal/handler/app/order/closeorderhandler.go b/internal/handler/admin/log/updateLogSettingHandler.go similarity index 57% rename from internal/handler/app/order/closeorderhandler.go rename to internal/handler/admin/log/updateLogSettingHandler.go index bba2210..91aa2c8 100644 --- a/internal/handler/app/order/closeorderhandler.go +++ b/internal/handler/admin/log/updateLogSettingHandler.go @@ -1,17 +1,17 @@ -package order +package log import ( "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/order" + "github.com/perfect-panel/server/internal/logic/admin/log" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/result" ) -// Close order -func CloseOrderHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { +// Update log setting +func UpdateLogSettingHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { - var req types.CloseOrderRequest + var req types.LogSetting _ = c.ShouldBind(&req) validateErr := svcCtx.Validate(&req) if validateErr != nil { @@ -19,8 +19,8 @@ func CloseOrderHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return } - l := order.NewCloseOrderLogic(c.Request.Context(), svcCtx) - err := l.CloseOrder(&req) + l := log.NewUpdateLogSettingLogic(c.Request.Context(), svcCtx) + err := l.UpdateLogSetting(&req) result.HttpResult(c, nil, err) } } diff --git a/internal/handler/admin/marketing/createQuotaTaskHandler.go b/internal/handler/admin/marketing/createQuotaTaskHandler.go new file mode 100644 index 0000000..0fb088b --- /dev/null +++ b/internal/handler/admin/marketing/createQuotaTaskHandler.go @@ -0,0 +1,26 @@ +package marketing + +import ( + "github.com/gin-gonic/gin" + "github.com/perfect-panel/server/internal/logic/admin/marketing" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/result" +) + +// Create a quota task +func CreateQuotaTaskHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { + return func(c *gin.Context) { + var req types.CreateQuotaTaskRequest + _ = c.ShouldBind(&req) + validateErr := svcCtx.Validate(&req) + if validateErr != nil { + result.ParamErrorResult(c, validateErr) + return + } + + l := marketing.NewCreateQuotaTaskLogic(c.Request.Context(), svcCtx) + err := l.CreateQuotaTask(&req) + result.HttpResult(c, nil, err) + } +} diff --git a/internal/handler/app/auth/checkHandler.go b/internal/handler/admin/marketing/queryQuotaTaskListHandler.go similarity index 53% rename from internal/handler/app/auth/checkHandler.go rename to internal/handler/admin/marketing/queryQuotaTaskListHandler.go index eab22c8..3aaebdc 100644 --- a/internal/handler/app/auth/checkHandler.go +++ b/internal/handler/admin/marketing/queryQuotaTaskListHandler.go @@ -1,17 +1,17 @@ -package auth +package marketing import ( "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/auth" + "github.com/perfect-panel/server/internal/logic/admin/marketing" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/result" ) -// Check Account -func CheckHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { +// Query quota task list +func QueryQuotaTaskListHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { - var req types.AppAuthCheckRequest + var req types.QueryQuotaTaskListRequest _ = c.ShouldBind(&req) validateErr := svcCtx.Validate(&req) if validateErr != nil { @@ -19,8 +19,8 @@ func CheckHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return } - l := auth.NewCheckLogic(c, svcCtx) - resp, err := l.Check(&req) + l := marketing.NewQueryQuotaTaskListLogic(c.Request.Context(), svcCtx) + resp, err := l.QueryQuotaTaskList(&req) result.HttpResult(c, resp, err) } } diff --git a/internal/handler/admin/marketing/queryQuotaTaskPreCountHandler.go b/internal/handler/admin/marketing/queryQuotaTaskPreCountHandler.go new file mode 100644 index 0000000..bcf6bd7 --- /dev/null +++ b/internal/handler/admin/marketing/queryQuotaTaskPreCountHandler.go @@ -0,0 +1,26 @@ +package marketing + +import ( + "github.com/gin-gonic/gin" + "github.com/perfect-panel/server/internal/logic/admin/marketing" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/result" +) + +// Query quota task pre-count +func QueryQuotaTaskPreCountHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { + return func(c *gin.Context) { + var req types.QueryQuotaTaskPreCountRequest + _ = c.ShouldBind(&req) + validateErr := svcCtx.Validate(&req) + if validateErr != nil { + result.ParamErrorResult(c, validateErr) + return + } + + l := marketing.NewQueryQuotaTaskPreCountLogic(c.Request.Context(), svcCtx) + resp, err := l.QueryQuotaTaskPreCount(&req) + result.HttpResult(c, resp, err) + } +} diff --git a/internal/handler/admin/marketing/queryQuotaTaskStatusHandler.go b/internal/handler/admin/marketing/queryQuotaTaskStatusHandler.go new file mode 100644 index 0000000..8d6cf9c --- /dev/null +++ b/internal/handler/admin/marketing/queryQuotaTaskStatusHandler.go @@ -0,0 +1,26 @@ +package marketing + +import ( + "github.com/gin-gonic/gin" + "github.com/perfect-panel/server/internal/logic/admin/marketing" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/result" +) + +// Query quota task status +func QueryQuotaTaskStatusHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { + return func(c *gin.Context) { + var req types.QueryQuotaTaskStatusRequest + _ = c.ShouldBind(&req) + validateErr := svcCtx.Validate(&req) + if validateErr != nil { + result.ParamErrorResult(c, validateErr) + return + } + + l := marketing.NewQueryQuotaTaskStatusLogic(c.Request.Context(), svcCtx) + resp, err := l.QueryQuotaTaskStatus(&req) + result.HttpResult(c, resp, err) + } +} diff --git a/internal/handler/admin/server/batchDeleteNodeGroupHandler.go b/internal/handler/admin/server/batchDeleteNodeGroupHandler.go deleted file mode 100644 index 22d0062..0000000 --- a/internal/handler/admin/server/batchDeleteNodeGroupHandler.go +++ /dev/null @@ -1,26 +0,0 @@ -package server - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/admin/server" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/result" -) - -// Batch delete node group -func BatchDeleteNodeGroupHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - var req types.BatchDeleteNodeGroupRequest - _ = c.ShouldBind(&req) - validateErr := svcCtx.Validate(&req) - if validateErr != nil { - result.ParamErrorResult(c, validateErr) - return - } - - l := server.NewBatchDeleteNodeGroupLogic(c.Request.Context(), svcCtx) - err := l.BatchDeleteNodeGroup(&req) - result.HttpResult(c, nil, err) - } -} diff --git a/internal/handler/admin/server/createNodeHandler.go b/internal/handler/admin/server/createNodeHandler.go index cac4455..e872b09 100644 --- a/internal/handler/admin/server/createNodeHandler.go +++ b/internal/handler/admin/server/createNodeHandler.go @@ -8,7 +8,7 @@ import ( "github.com/perfect-panel/server/pkg/result" ) -// Create node +// Create Node func CreateNodeHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { var req types.CreateNodeRequest diff --git a/internal/handler/admin/server/createRuleGroupHandler.go b/internal/handler/admin/server/createRuleGroupHandler.go deleted file mode 100644 index 89a436a..0000000 --- a/internal/handler/admin/server/createRuleGroupHandler.go +++ /dev/null @@ -1,26 +0,0 @@ -package server - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/admin/server" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/result" -) - -// CreateRuleGroupHandler Create rule group -func CreateRuleGroupHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - var req types.CreateRuleGroupRequest - _ = c.ShouldBind(&req) - validateErr := svcCtx.Validate(&req) - if validateErr != nil { - result.ParamErrorResult(c, validateErr) - return - } - - l := server.NewCreateRuleGroupLogic(c.Request.Context(), svcCtx) - err := l.CreateRuleGroup(&req) - result.HttpResult(c, nil, err) - } -} diff --git a/internal/handler/admin/server/deleteNodeGroupHandler.go b/internal/handler/admin/server/createServerHandler.go similarity index 66% rename from internal/handler/admin/server/deleteNodeGroupHandler.go rename to internal/handler/admin/server/createServerHandler.go index d27c6b9..2068122 100644 --- a/internal/handler/admin/server/deleteNodeGroupHandler.go +++ b/internal/handler/admin/server/createServerHandler.go @@ -8,10 +8,10 @@ import ( "github.com/perfect-panel/server/pkg/result" ) -// Delete node group -func DeleteNodeGroupHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { +// CreateServerHandler Create Server +func CreateServerHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { - var req types.DeleteNodeGroupRequest + var req types.CreateServerRequest _ = c.ShouldBind(&req) validateErr := svcCtx.Validate(&req) if validateErr != nil { @@ -19,8 +19,8 @@ func DeleteNodeGroupHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return } - l := server.NewDeleteNodeGroupLogic(c.Request.Context(), svcCtx) - err := l.DeleteNodeGroup(&req) + l := server.NewCreateServerLogic(c.Request.Context(), svcCtx) + err := l.CreateServer(&req) result.HttpResult(c, nil, err) } } diff --git a/internal/handler/admin/server/deleteNodeHandler.go b/internal/handler/admin/server/deleteNodeHandler.go index 76d3d49..37ac80b 100644 --- a/internal/handler/admin/server/deleteNodeHandler.go +++ b/internal/handler/admin/server/deleteNodeHandler.go @@ -8,7 +8,7 @@ import ( "github.com/perfect-panel/server/pkg/result" ) -// Delete node +// Delete Node func DeleteNodeHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { var req types.DeleteNodeRequest diff --git a/internal/handler/admin/server/nodeSortHandler.go b/internal/handler/admin/server/deleteServerHandler.go similarity index 68% rename from internal/handler/admin/server/nodeSortHandler.go rename to internal/handler/admin/server/deleteServerHandler.go index 2b4f031..677fb17 100644 --- a/internal/handler/admin/server/nodeSortHandler.go +++ b/internal/handler/admin/server/deleteServerHandler.go @@ -8,10 +8,10 @@ import ( "github.com/perfect-panel/server/pkg/result" ) -// Node sort -func NodeSortHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { +// Delete Server +func DeleteServerHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { - var req types.NodeSortRequest + var req types.DeleteServerRequest _ = c.ShouldBind(&req) validateErr := svcCtx.Validate(&req) if validateErr != nil { @@ -19,8 +19,8 @@ func NodeSortHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return } - l := server.NewNodeSortLogic(c.Request.Context(), svcCtx) - err := l.NodeSort(&req) + l := server.NewDeleteServerLogic(c.Request.Context(), svcCtx) + err := l.DeleteServer(&req) result.HttpResult(c, nil, err) } } diff --git a/internal/handler/admin/server/getNodeDetailHandler.go b/internal/handler/admin/server/filterNodeListHandler.go similarity index 66% rename from internal/handler/admin/server/getNodeDetailHandler.go rename to internal/handler/admin/server/filterNodeListHandler.go index 06bcaab..5e154ca 100644 --- a/internal/handler/admin/server/getNodeDetailHandler.go +++ b/internal/handler/admin/server/filterNodeListHandler.go @@ -8,10 +8,10 @@ import ( "github.com/perfect-panel/server/pkg/result" ) -// Get node detail -func GetNodeDetailHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { +// Filter Node List +func FilterNodeListHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { - var req types.GetDetailRequest + var req types.FilterNodeListRequest _ = c.ShouldBind(&req) validateErr := svcCtx.Validate(&req) if validateErr != nil { @@ -19,8 +19,8 @@ func GetNodeDetailHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return } - l := server.NewGetNodeDetailLogic(c.Request.Context(), svcCtx) - resp, err := l.GetNodeDetail(&req) + l := server.NewFilterNodeListLogic(c.Request.Context(), svcCtx) + resp, err := l.FilterNodeList(&req) result.HttpResult(c, resp, err) } } diff --git a/internal/handler/admin/server/filterServerListHandler.go b/internal/handler/admin/server/filterServerListHandler.go new file mode 100644 index 0000000..9e6cb7b --- /dev/null +++ b/internal/handler/admin/server/filterServerListHandler.go @@ -0,0 +1,26 @@ +package server + +import ( + "github.com/gin-gonic/gin" + "github.com/perfect-panel/server/internal/logic/admin/server" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/result" +) + +// FilterServerListHandler Filter Server List +func FilterServerListHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { + return func(c *gin.Context) { + var req types.FilterServerListRequest + _ = c.ShouldBind(&req) + validateErr := svcCtx.Validate(&req) + if validateErr != nil { + result.ParamErrorResult(c, validateErr) + return + } + + l := server.NewFilterServerListLogic(c.Request.Context(), svcCtx) + resp, err := l.FilterServerList(&req) + result.HttpResult(c, resp, err) + } +} diff --git a/internal/handler/admin/server/getNodeListHandler.go b/internal/handler/admin/server/getServerProtocolsHandler.go similarity index 64% rename from internal/handler/admin/server/getNodeListHandler.go rename to internal/handler/admin/server/getServerProtocolsHandler.go index 3bfa07d..14238ca 100644 --- a/internal/handler/admin/server/getNodeListHandler.go +++ b/internal/handler/admin/server/getServerProtocolsHandler.go @@ -8,10 +8,10 @@ import ( "github.com/perfect-panel/server/pkg/result" ) -// Get node list -func GetNodeListHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { +// Get Server Protocols +func GetServerProtocolsHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { - var req types.GetNodeServerListRequest + var req types.GetServerProtocolsRequest _ = c.ShouldBind(&req) validateErr := svcCtx.Validate(&req) if validateErr != nil { @@ -19,8 +19,8 @@ func GetNodeListHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return } - l := server.NewGetNodeListLogic(c.Request.Context(), svcCtx) - resp, err := l.GetNodeList(&req) + l := server.NewGetServerProtocolsLogic(c.Request.Context(), svcCtx) + resp, err := l.GetServerProtocols(&req) result.HttpResult(c, resp, err) } } diff --git a/internal/handler/admin/server/getNodeGroupListHandler.go b/internal/handler/admin/server/hasMigrateSeverNodeHandler.go similarity index 53% rename from internal/handler/admin/server/getNodeGroupListHandler.go rename to internal/handler/admin/server/hasMigrateSeverNodeHandler.go index 3d741d0..6088577 100644 --- a/internal/handler/admin/server/getNodeGroupListHandler.go +++ b/internal/handler/admin/server/hasMigrateSeverNodeHandler.go @@ -7,12 +7,12 @@ import ( "github.com/perfect-panel/server/pkg/result" ) -// Get node group list -func GetNodeGroupListHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { +// Check if there is any server or node to migrate +func HasMigrateSeverNodeHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { - l := server.NewGetNodeGroupListLogic(c.Request.Context(), svcCtx) - resp, err := l.GetNodeGroupList() + l := server.NewHasMigrateSeverNodeLogic(c.Request.Context(), svcCtx) + resp, err := l.HasMigrateSeverNode() result.HttpResult(c, resp, err) } } diff --git a/internal/handler/admin/server/getRuleGroupListHandler.go b/internal/handler/admin/server/migrateServerNodeHandler.go similarity index 54% rename from internal/handler/admin/server/getRuleGroupListHandler.go rename to internal/handler/admin/server/migrateServerNodeHandler.go index 8f8fba2..8f8c842 100644 --- a/internal/handler/admin/server/getRuleGroupListHandler.go +++ b/internal/handler/admin/server/migrateServerNodeHandler.go @@ -7,12 +7,12 @@ import ( "github.com/perfect-panel/server/pkg/result" ) -// Get rule group list -func GetRuleGroupListHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { +// Migrate server and node data to new database +func MigrateServerNodeHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { - l := server.NewGetRuleGroupListLogic(c.Request.Context(), svcCtx) - resp, err := l.GetRuleGroupList() + l := server.NewMigrateServerNodeLogic(c.Request.Context(), svcCtx) + resp, err := l.MigrateServerNode() result.HttpResult(c, resp, err) } } diff --git a/internal/handler/admin/server/getNodeTagListHandler.go b/internal/handler/admin/server/queryNodeTagHandler.go similarity index 58% rename from internal/handler/admin/server/getNodeTagListHandler.go rename to internal/handler/admin/server/queryNodeTagHandler.go index aa0e1ff..fa963cc 100644 --- a/internal/handler/admin/server/getNodeTagListHandler.go +++ b/internal/handler/admin/server/queryNodeTagHandler.go @@ -7,12 +7,12 @@ import ( "github.com/perfect-panel/server/pkg/result" ) -// Get node tag list -func GetNodeTagListHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { +// Query all node tags +func QueryNodeTagHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { - l := server.NewGetNodeTagListLogic(c.Request.Context(), svcCtx) - resp, err := l.GetNodeTagList() + l := server.NewQueryNodeTagLogic(c.Request.Context(), svcCtx) + resp, err := l.QueryNodeTag() result.HttpResult(c, resp, err) } } diff --git a/internal/handler/admin/server/deleteRuleGroupHandler.go b/internal/handler/admin/server/resetSortWithNodeHandler.go similarity index 66% rename from internal/handler/admin/server/deleteRuleGroupHandler.go rename to internal/handler/admin/server/resetSortWithNodeHandler.go index 8daddfd..4b8b14c 100644 --- a/internal/handler/admin/server/deleteRuleGroupHandler.go +++ b/internal/handler/admin/server/resetSortWithNodeHandler.go @@ -8,10 +8,10 @@ import ( "github.com/perfect-panel/server/pkg/result" ) -// Delete rule group -func DeleteRuleGroupHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { +// Reset node sort +func ResetSortWithNodeHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { - var req types.DeleteRuleGroupRequest + var req types.ResetSortRequest _ = c.ShouldBind(&req) validateErr := svcCtx.Validate(&req) if validateErr != nil { @@ -19,8 +19,8 @@ func DeleteRuleGroupHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return } - l := server.NewDeleteRuleGroupLogic(c.Request.Context(), svcCtx) - err := l.DeleteRuleGroup(&req) + l := server.NewResetSortWithNodeLogic(c.Request.Context(), svcCtx) + err := l.ResetSortWithNode(&req) result.HttpResult(c, nil, err) } } diff --git a/internal/handler/admin/server/resetSortWithServerHandler.go b/internal/handler/admin/server/resetSortWithServerHandler.go new file mode 100644 index 0000000..7adbecb --- /dev/null +++ b/internal/handler/admin/server/resetSortWithServerHandler.go @@ -0,0 +1,26 @@ +package server + +import ( + "github.com/gin-gonic/gin" + "github.com/perfect-panel/server/internal/logic/admin/server" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/result" +) + +// Reset server sort +func ResetSortWithServerHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { + return func(c *gin.Context) { + var req types.ResetSortRequest + _ = c.ShouldBind(&req) + validateErr := svcCtx.Validate(&req) + if validateErr != nil { + result.ParamErrorResult(c, validateErr) + return + } + + l := server.NewResetSortWithServerLogic(c.Request.Context(), svcCtx) + err := l.ResetSortWithServer(&req) + result.HttpResult(c, nil, err) + } +} diff --git a/internal/handler/admin/server/createNodeGroupHandler.go b/internal/handler/admin/server/toggleNodeStatusHandler.go similarity index 66% rename from internal/handler/admin/server/createNodeGroupHandler.go rename to internal/handler/admin/server/toggleNodeStatusHandler.go index edbc8f9..67144ad 100644 --- a/internal/handler/admin/server/createNodeGroupHandler.go +++ b/internal/handler/admin/server/toggleNodeStatusHandler.go @@ -8,10 +8,10 @@ import ( "github.com/perfect-panel/server/pkg/result" ) -// Create node group -func CreateNodeGroupHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { +// Toggle Node Status +func ToggleNodeStatusHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { - var req types.CreateNodeGroupRequest + var req types.ToggleNodeStatusRequest _ = c.ShouldBind(&req) validateErr := svcCtx.Validate(&req) if validateErr != nil { @@ -19,8 +19,8 @@ func CreateNodeGroupHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return } - l := server.NewCreateNodeGroupLogic(c.Request.Context(), svcCtx) - err := l.CreateNodeGroup(&req) + l := server.NewToggleNodeStatusLogic(c.Request.Context(), svcCtx) + err := l.ToggleNodeStatus(&req) result.HttpResult(c, nil, err) } } diff --git a/internal/handler/admin/server/updateNodeGroupHandler.go b/internal/handler/admin/server/updateNodeGroupHandler.go deleted file mode 100644 index 9994bf7..0000000 --- a/internal/handler/admin/server/updateNodeGroupHandler.go +++ /dev/null @@ -1,26 +0,0 @@ -package server - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/admin/server" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/result" -) - -// Update node group -func UpdateNodeGroupHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - var req types.UpdateNodeGroupRequest - _ = c.ShouldBind(&req) - validateErr := svcCtx.Validate(&req) - if validateErr != nil { - result.ParamErrorResult(c, validateErr) - return - } - - l := server.NewUpdateNodeGroupLogic(c.Request.Context(), svcCtx) - err := l.UpdateNodeGroup(&req) - result.HttpResult(c, nil, err) - } -} diff --git a/internal/handler/admin/server/updateNodeHandler.go b/internal/handler/admin/server/updateNodeHandler.go index 58e8690..af19537 100644 --- a/internal/handler/admin/server/updateNodeHandler.go +++ b/internal/handler/admin/server/updateNodeHandler.go @@ -8,7 +8,7 @@ import ( "github.com/perfect-panel/server/pkg/result" ) -// Update node +// Update Node func UpdateNodeHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { var req types.UpdateNodeRequest diff --git a/internal/handler/admin/server/updateRuleGroupHandler.go b/internal/handler/admin/server/updateRuleGroupHandler.go deleted file mode 100644 index 224cb35..0000000 --- a/internal/handler/admin/server/updateRuleGroupHandler.go +++ /dev/null @@ -1,26 +0,0 @@ -package server - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/admin/server" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/result" -) - -// Update rule group -func UpdateRuleGroupHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - var req types.UpdateRuleGroupRequest - _ = c.ShouldBind(&req) - validateErr := svcCtx.Validate(&req) - if validateErr != nil { - result.ParamErrorResult(c, validateErr) - return - } - - l := server.NewUpdateRuleGroupLogic(c.Request.Context(), svcCtx) - err := l.UpdateRuleGroup(&req) - result.HttpResult(c, nil, err) - } -} diff --git a/internal/handler/admin/server/batchDeleteNodeHandler.go b/internal/handler/admin/server/updateServerHandler.go similarity index 66% rename from internal/handler/admin/server/batchDeleteNodeHandler.go rename to internal/handler/admin/server/updateServerHandler.go index ab5e3c3..24570c6 100644 --- a/internal/handler/admin/server/batchDeleteNodeHandler.go +++ b/internal/handler/admin/server/updateServerHandler.go @@ -8,10 +8,10 @@ import ( "github.com/perfect-panel/server/pkg/result" ) -// Batch delete node -func BatchDeleteNodeHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { +// Update Server +func UpdateServerHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { - var req types.BatchDeleteNodeRequest + var req types.UpdateServerRequest _ = c.ShouldBind(&req) validateErr := svcCtx.Validate(&req) if validateErr != nil { @@ -19,8 +19,8 @@ func BatchDeleteNodeHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return } - l := server.NewBatchDeleteNodeLogic(c.Request.Context(), svcCtx) - err := l.BatchDeleteNode(&req) + l := server.NewUpdateServerLogic(c.Request.Context(), svcCtx) + err := l.UpdateServer(&req) result.HttpResult(c, nil, err) } } diff --git a/internal/handler/admin/system/createApplicationHandler.go b/internal/handler/admin/system/createApplicationHandler.go deleted file mode 100644 index d429250..0000000 --- a/internal/handler/admin/system/createApplicationHandler.go +++ /dev/null @@ -1,26 +0,0 @@ -package system - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/admin/system" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/result" -) - -// Create application -func CreateApplicationHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - var req types.CreateApplicationRequest - _ = c.ShouldBind(&req) - validateErr := svcCtx.Validate(&req) - if validateErr != nil { - result.ParamErrorResult(c, validateErr) - return - } - - l := system.NewCreateApplicationLogic(c.Request.Context(), svcCtx) - err := l.CreateApplication(&req) - result.HttpResult(c, nil, err) - } -} diff --git a/internal/handler/admin/system/createApplicationVersionHandler.go b/internal/handler/admin/system/createApplicationVersionHandler.go deleted file mode 100644 index bc92fa2..0000000 --- a/internal/handler/admin/system/createApplicationVersionHandler.go +++ /dev/null @@ -1,26 +0,0 @@ -package system - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/admin/system" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/result" -) - -// Create application version -func CreateApplicationVersionHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - var req types.CreateApplicationVersionRequest - _ = c.ShouldBind(&req) - validateErr := svcCtx.Validate(&req) - if validateErr != nil { - result.ParamErrorResult(c, validateErr) - return - } - - l := system.NewCreateApplicationVersionLogic(c.Request.Context(), svcCtx) - err := l.CreateApplicationVersion(&req) - result.HttpResult(c, nil, err) - } -} diff --git a/internal/handler/admin/system/deleteApplicationHandler.go b/internal/handler/admin/system/deleteApplicationHandler.go deleted file mode 100644 index a015e27..0000000 --- a/internal/handler/admin/system/deleteApplicationHandler.go +++ /dev/null @@ -1,26 +0,0 @@ -package system - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/admin/system" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/result" -) - -// Delete application -func DeleteApplicationHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - var req types.DeleteApplicationRequest - _ = c.ShouldBind(&req) - validateErr := svcCtx.Validate(&req) - if validateErr != nil { - result.ParamErrorResult(c, validateErr) - return - } - - l := system.NewDeleteApplicationLogic(c.Request.Context(), svcCtx) - err := l.DeleteApplication(&req) - result.HttpResult(c, nil, err) - } -} diff --git a/internal/handler/admin/system/deleteApplicationVersionHandler.go b/internal/handler/admin/system/deleteApplicationVersionHandler.go deleted file mode 100644 index 2bb8109..0000000 --- a/internal/handler/admin/system/deleteApplicationVersionHandler.go +++ /dev/null @@ -1,26 +0,0 @@ -package system - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/admin/system" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/result" -) - -// Delete application -func DeleteApplicationVersionHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - var req types.DeleteApplicationVersionRequest - _ = c.ShouldBind(&req) - validateErr := svcCtx.Validate(&req) - if validateErr != nil { - result.ParamErrorResult(c, validateErr) - return - } - - l := system.NewDeleteApplicationVersionLogic(c.Request.Context(), svcCtx) - err := l.DeleteApplicationVersion(&req) - result.HttpResult(c, nil, err) - } -} diff --git a/internal/handler/admin/system/getApplicationConfigHandler.go b/internal/handler/admin/system/getApplicationConfigHandler.go deleted file mode 100644 index 5d9cf9a..0000000 --- a/internal/handler/admin/system/getApplicationConfigHandler.go +++ /dev/null @@ -1,18 +0,0 @@ -package system - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/admin/system" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/result" -) - -// get application config -func GetApplicationConfigHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - - l := system.NewGetApplicationConfigLogic(c.Request.Context(), svcCtx) - resp, err := l.GetApplicationConfig() - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/admin/system/getApplicationHandler.go b/internal/handler/admin/system/getApplicationHandler.go deleted file mode 100644 index 0332928..0000000 --- a/internal/handler/admin/system/getApplicationHandler.go +++ /dev/null @@ -1,18 +0,0 @@ -package system - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/admin/system" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/result" -) - -// Get application -func GetApplicationHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - - l := system.NewGetApplicationLogic(c.Request.Context(), svcCtx) - resp, err := l.GetApplication() - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/admin/system/getSubscribeTypeHandler.go b/internal/handler/admin/system/getSubscribeTypeHandler.go deleted file mode 100644 index 7aae564..0000000 --- a/internal/handler/admin/system/getSubscribeTypeHandler.go +++ /dev/null @@ -1,18 +0,0 @@ -package system - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/admin/system" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/result" -) - -// Get subscribe type -func GetSubscribeTypeHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - - l := system.NewGetSubscribeTypeLogic(c.Request.Context(), svcCtx) - resp, err := l.GetSubscribeType() - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/admin/system/updateApplicationConfigHandler.go b/internal/handler/admin/system/updateApplicationConfigHandler.go deleted file mode 100644 index be766f0..0000000 --- a/internal/handler/admin/system/updateApplicationConfigHandler.go +++ /dev/null @@ -1,26 +0,0 @@ -package system - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/admin/system" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/result" -) - -// update application config -func UpdateApplicationConfigHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - var req types.ApplicationConfig - _ = c.ShouldBind(&req) - validateErr := svcCtx.Validate(&req) - if validateErr != nil { - result.ParamErrorResult(c, validateErr) - return - } - - l := system.NewUpdateApplicationConfigLogic(c.Request.Context(), svcCtx) - err := l.UpdateApplicationConfig(&req) - result.HttpResult(c, nil, err) - } -} diff --git a/internal/handler/admin/system/updateApplicationHandler.go b/internal/handler/admin/system/updateApplicationHandler.go deleted file mode 100644 index 55c0498..0000000 --- a/internal/handler/admin/system/updateApplicationHandler.go +++ /dev/null @@ -1,26 +0,0 @@ -package system - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/admin/system" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/result" -) - -// Update application -func UpdateApplicationHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - var req types.UpdateApplicationRequest - _ = c.ShouldBind(&req) - validateErr := svcCtx.Validate(&req) - if validateErr != nil { - result.ParamErrorResult(c, validateErr) - return - } - - l := system.NewUpdateApplicationLogic(c.Request.Context(), svcCtx) - err := l.UpdateApplication(&req) - result.HttpResult(c, nil, err) - } -} diff --git a/internal/handler/admin/system/updateApplicationVersionHandler.go b/internal/handler/admin/system/updateApplicationVersionHandler.go deleted file mode 100644 index 1975338..0000000 --- a/internal/handler/admin/system/updateApplicationVersionHandler.go +++ /dev/null @@ -1,26 +0,0 @@ -package system - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/admin/system" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/result" -) - -// Update application version -func UpdateApplicationVersionHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - var req types.UpdateApplicationVersionRequest - _ = c.ShouldBind(&req) - validateErr := svcCtx.Validate(&req) - if validateErr != nil { - result.ParamErrorResult(c, validateErr) - return - } - - l := system.NewUpdateApplicationVersionLogic(c.Request.Context(), svcCtx) - err := l.UpdateApplicationVersion(&req) - result.HttpResult(c, nil, err) - } -} diff --git a/internal/handler/admin/user/getUserSubscribeResetTrafficLogsHandler.go b/internal/handler/admin/user/getUserSubscribeResetTrafficLogsHandler.go new file mode 100644 index 0000000..0f7525d --- /dev/null +++ b/internal/handler/admin/user/getUserSubscribeResetTrafficLogsHandler.go @@ -0,0 +1,26 @@ +package user + +import ( + "github.com/gin-gonic/gin" + "github.com/perfect-panel/server/internal/logic/admin/user" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/result" +) + +// Get user subcribe reset traffic logs +func GetUserSubscribeResetTrafficLogsHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { + return func(c *gin.Context) { + var req types.GetUserSubscribeResetTrafficLogsRequest + _ = c.ShouldBind(&req) + validateErr := svcCtx.Validate(&req) + if validateErr != nil { + result.ParamErrorResult(c, validateErr) + return + } + + l := user.NewGetUserSubscribeResetTrafficLogsLogic(c.Request.Context(), svcCtx) + resp, err := l.GetUserSubscribeResetTrafficLogs(&req) + result.HttpResult(c, resp, err) + } +} diff --git a/internal/handler/app/auth/loginHandler.go b/internal/handler/app/auth/loginHandler.go deleted file mode 100644 index 4d6cd27..0000000 --- a/internal/handler/app/auth/loginHandler.go +++ /dev/null @@ -1,42 +0,0 @@ -package auth - -import ( - "time" - - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/auth" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/result" - "github.com/perfect-panel/server/pkg/turnstile" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -// Login -func LoginHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - var req types.AppAuthRequest - _ = c.ShouldBind(&req) - validateErr := svcCtx.Validate(&req) - if validateErr != nil { - result.ParamErrorResult(c, validateErr) - return - } - - if svcCtx.Config.Verify.LoginVerify { - verifyTurns := turnstile.New(turnstile.Config{ - Secret: svcCtx.Config.Verify.TurnstileSecret, - Timeout: 3 * time.Second, - }) - if verify, err := verifyTurns.Verify(c, req.CfToken, c.ClientIP()); err != nil || !verify { - err = errors.Wrapf(xerr.NewErrCode(xerr.TooManyRequests), "error: %v, verify: %v", err, verify) - result.HttpResult(c, nil, err) - return - } - } - l := auth.NewLoginLogic(c, svcCtx) - resp, err := l.Login(&req) - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/app/auth/registerHandler.go b/internal/handler/app/auth/registerHandler.go deleted file mode 100644 index 44cc6e0..0000000 --- a/internal/handler/app/auth/registerHandler.go +++ /dev/null @@ -1,43 +0,0 @@ -package auth - -import ( - "time" - - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/auth" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/result" - "github.com/perfect-panel/server/pkg/turnstile" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -// Register -func RegisterHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - var req types.AppAuthRequest - _ = c.ShouldBind(&req) - validateErr := svcCtx.Validate(&req) - if validateErr != nil { - result.ParamErrorResult(c, validateErr) - return - } - // get client ip - if svcCtx.Config.Verify.RegisterVerify { - verifyTurns := turnstile.New(turnstile.Config{ - Secret: svcCtx.Config.Verify.TurnstileSecret, - Timeout: 3 * time.Second, - }) - if verify, err := verifyTurns.Verify(c, req.CfToken, c.ClientIP()); err != nil || !verify { - err = errors.Wrapf(xerr.NewErrCode(xerr.TooManyRequests), "error: %v, verify: %v", err, verify) - result.HttpResult(c, nil, err) - return - } - } - - l := auth.NewRegisterLogic(c, svcCtx) - resp, err := l.Register(&req) - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/app/auth/resetPasswordHandler.go b/internal/handler/app/auth/resetPasswordHandler.go deleted file mode 100644 index 82fbc41..0000000 --- a/internal/handler/app/auth/resetPasswordHandler.go +++ /dev/null @@ -1,41 +0,0 @@ -package auth - -import ( - "time" - - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/auth" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/result" - "github.com/perfect-panel/server/pkg/turnstile" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -// Reset Password -func ResetPasswordHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - var req types.AppAuthRequest - _ = c.ShouldBind(&req) - validateErr := svcCtx.Validate(&req) - if validateErr != nil { - result.ParamErrorResult(c, validateErr) - return - } - if svcCtx.Config.Verify.ResetPasswordVerify { - verifyTurns := turnstile.New(turnstile.Config{ - Secret: svcCtx.Config.Verify.TurnstileSecret, - Timeout: 3 * time.Second, - }) - if verify, err := verifyTurns.Verify(c, req.CfToken, c.ClientIP()); err != nil || !verify { - err = errors.Wrapf(xerr.NewErrCode(xerr.TooManyRequests), "error: %v, verify: %v", err, verify) - result.HttpResult(c, nil, err) - return - } - } - l := auth.NewResetPasswordLogic(c, svcCtx) - resp, err := l.ResetPassword(&req) - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/app/document/querydocumentlisthandler.go b/internal/handler/app/document/querydocumentlisthandler.go deleted file mode 100644 index d8cb7de..0000000 --- a/internal/handler/app/document/querydocumentlisthandler.go +++ /dev/null @@ -1,18 +0,0 @@ -package document - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/document" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/result" -) - -// Get document list -func QueryDocumentListHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - - l := document.NewQueryDocumentListLogic(c.Request.Context(), svcCtx) - resp, err := l.QueryDocumentList() - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/app/node/getRuleGroupListHandler.go b/internal/handler/app/node/getRuleGroupListHandler.go deleted file mode 100644 index e48750e..0000000 --- a/internal/handler/app/node/getRuleGroupListHandler.go +++ /dev/null @@ -1,18 +0,0 @@ -package node - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/node" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/result" -) - -// Get rule group list -func GetRuleGroupListHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - - l := node.NewGetRuleGroupListLogic(c.Request.Context(), svcCtx) - resp, err := l.GetRuleGroupList() - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/app/order/purchasehandler.go b/internal/handler/app/order/purchasehandler.go deleted file mode 100644 index 6aded64..0000000 --- a/internal/handler/app/order/purchasehandler.go +++ /dev/null @@ -1,26 +0,0 @@ -package order - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/order" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/result" -) - -// purchase Subscription -func PurchaseHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - var req types.PurchaseOrderRequest - _ = c.ShouldBind(&req) - validateErr := svcCtx.Validate(&req) - if validateErr != nil { - result.ParamErrorResult(c, validateErr) - return - } - - l := order.NewPurchaseLogic(c.Request.Context(), svcCtx) - resp, err := l.Purchase(&req) - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/app/order/rechargehandler.go b/internal/handler/app/order/rechargehandler.go deleted file mode 100644 index 9d0a23e..0000000 --- a/internal/handler/app/order/rechargehandler.go +++ /dev/null @@ -1,26 +0,0 @@ -package order - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/order" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/result" -) - -// Recharge -func RechargeHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - var req types.RechargeOrderRequest - _ = c.ShouldBind(&req) - validateErr := svcCtx.Validate(&req) - if validateErr != nil { - result.ParamErrorResult(c, validateErr) - return - } - - l := order.NewRechargeLogic(c.Request.Context(), svcCtx) - resp, err := l.Recharge(&req) - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/app/order/renewalhandler.go b/internal/handler/app/order/renewalhandler.go deleted file mode 100644 index 2de271e..0000000 --- a/internal/handler/app/order/renewalhandler.go +++ /dev/null @@ -1,26 +0,0 @@ -package order - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/order" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/result" -) - -// Renewal Subscription -func RenewalHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - var req types.RenewalOrderRequest - _ = c.ShouldBind(&req) - validateErr := svcCtx.Validate(&req) - if validateErr != nil { - result.ParamErrorResult(c, validateErr) - return - } - - l := order.NewRenewalLogic(c.Request.Context(), svcCtx) - resp, err := l.Renewal(&req) - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/app/order/resettraffichandler.go b/internal/handler/app/order/resettraffichandler.go deleted file mode 100644 index 3740794..0000000 --- a/internal/handler/app/order/resettraffichandler.go +++ /dev/null @@ -1,26 +0,0 @@ -package order - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/order" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/result" -) - -// Reset traffic -func ResetTrafficHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - var req types.ResetTrafficOrderRequest - _ = c.ShouldBind(&req) - validateErr := svcCtx.Validate(&req) - if validateErr != nil { - result.ParamErrorResult(c, validateErr) - return - } - - l := order.NewResetTrafficLogic(c.Request.Context(), svcCtx) - resp, err := l.ResetTraffic(&req) - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/app/payment/getavailablepaymentmethodshandler.go b/internal/handler/app/payment/getavailablepaymentmethodshandler.go deleted file mode 100644 index a665a33..0000000 --- a/internal/handler/app/payment/getavailablepaymentmethodshandler.go +++ /dev/null @@ -1,18 +0,0 @@ -package payment - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/payment" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/result" -) - -// Get available payment methods -func GetAvailablePaymentMethodsHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - - l := payment.NewGetAvailablePaymentMethodsLogic(c.Request.Context(), svcCtx) - resp, err := l.GetAvailablePaymentMethods() - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/app/subscribe/queryApplicationConfigHandler.go b/internal/handler/app/subscribe/queryApplicationConfigHandler.go deleted file mode 100644 index 611d2ab..0000000 --- a/internal/handler/app/subscribe/queryApplicationConfigHandler.go +++ /dev/null @@ -1,18 +0,0 @@ -package subscribe - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/subscribe" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/result" -) - -// Get application config -func QueryApplicationConfigHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - - l := subscribe.NewQueryApplicationConfigLogic(c.Request.Context(), svcCtx) - resp, err := l.QueryApplicationConfig() - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/app/subscribe/querySubscribeGroupListHandler.go b/internal/handler/app/subscribe/querySubscribeGroupListHandler.go deleted file mode 100644 index 972713c..0000000 --- a/internal/handler/app/subscribe/querySubscribeGroupListHandler.go +++ /dev/null @@ -1,18 +0,0 @@ -package subscribe - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/subscribe" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/result" -) - -// Get subscribe group list -func QuerySubscribeGroupListHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - - l := subscribe.NewQuerySubscribeGroupListLogic(c.Request.Context(), svcCtx) - resp, err := l.QuerySubscribeGroupList() - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/app/subscribe/querySubscribeListHandler.go b/internal/handler/app/subscribe/querySubscribeListHandler.go deleted file mode 100644 index 9e4d789..0000000 --- a/internal/handler/app/subscribe/querySubscribeListHandler.go +++ /dev/null @@ -1,18 +0,0 @@ -package subscribe - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/subscribe" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/result" -) - -// Get subscribe list -func QuerySubscribeListHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - - l := subscribe.NewQuerySubscribeListLogic(c.Request.Context(), svcCtx) - resp, err := l.QuerySubscribeList() - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/app/subscribe/queryUserAlreadySubscribeHandler.go b/internal/handler/app/subscribe/queryUserAlreadySubscribeHandler.go deleted file mode 100644 index 3541f2b..0000000 --- a/internal/handler/app/subscribe/queryUserAlreadySubscribeHandler.go +++ /dev/null @@ -1,18 +0,0 @@ -package subscribe - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/subscribe" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/result" -) - -// Get Already subscribed to package -func QueryUserAlreadySubscribeHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - - l := subscribe.NewQueryUserAlreadySubscribeLogic(c.Request.Context(), svcCtx) - resp, err := l.QueryUserAlreadySubscribe() - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/app/subscribe/queryUserAvailableUserSubscribeHandler.go b/internal/handler/app/subscribe/queryUserAvailableUserSubscribeHandler.go deleted file mode 100644 index 0107e9d..0000000 --- a/internal/handler/app/subscribe/queryUserAvailableUserSubscribeHandler.go +++ /dev/null @@ -1,26 +0,0 @@ -package subscribe - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/subscribe" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/result" -) - -// Get Available subscriptions for users -func QueryUserAvailableUserSubscribeHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - var req types.AppUserSubscribeRequest - _ = c.ShouldBind(&req) - validateErr := svcCtx.Validate(&req) - if validateErr != nil { - result.ParamErrorResult(c, validateErr) - return - } - - l := subscribe.NewQueryUserAvailableUserSubscribeLogic(c.Request.Context(), svcCtx) - resp, err := l.QueryUserAvailableUserSubscribe(&req) - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/app/subscribe/resetUserSubscribePeriodHandler.go b/internal/handler/app/subscribe/resetUserSubscribePeriodHandler.go deleted file mode 100644 index fc939b6..0000000 --- a/internal/handler/app/subscribe/resetUserSubscribePeriodHandler.go +++ /dev/null @@ -1,26 +0,0 @@ -package subscribe - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/subscribe" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/result" -) - -// Reset user subscription period -func ResetUserSubscribePeriodHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - var req types.UserSubscribeResetPeriodRequest - _ = c.ShouldBind(&req) - validateErr := svcCtx.Validate(&req) - if validateErr != nil { - result.ParamErrorResult(c, validateErr) - return - } - - l := subscribe.NewResetUserSubscribePeriodLogic(c.Request.Context(), svcCtx) - resp, err := l.ResetUserSubscribePeriod(&req) - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/app/user/deleteAccountHandler.go b/internal/handler/app/user/deleteAccountHandler.go deleted file mode 100644 index fd9d845..0000000 --- a/internal/handler/app/user/deleteAccountHandler.go +++ /dev/null @@ -1,26 +0,0 @@ -package user - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/result" -) - -// Delete Account -func DeleteAccountHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - var req types.DeleteAccountRequest - _ = c.ShouldBind(&req) - validateErr := svcCtx.Validate(&req) - if validateErr != nil { - result.ParamErrorResult(c, validateErr) - return - } - - l := user.NewDeleteAccountLogic(c.Request.Context(), svcCtx) - err := l.DeleteAccount(&req) - result.HttpResult(c, nil, err) - } -} diff --git a/internal/handler/app/user/getuseronlinetimestatisticshandler.go b/internal/handler/app/user/getuseronlinetimestatisticshandler.go deleted file mode 100644 index 15ad65c..0000000 --- a/internal/handler/app/user/getuseronlinetimestatisticshandler.go +++ /dev/null @@ -1,18 +0,0 @@ -package user - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/result" -) - -// Get user online time total -func GetUserOnlineTimeStatisticsHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - - l := user.NewGetUserOnlineTimeStatisticsLogic(c.Request.Context(), svcCtx) - resp, err := l.GetUserOnlineTimeStatistics() - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/app/user/getusersubscribetrafficlogshandler.go b/internal/handler/app/user/getusersubscribetrafficlogshandler.go deleted file mode 100644 index 977fbb9..0000000 --- a/internal/handler/app/user/getusersubscribetrafficlogshandler.go +++ /dev/null @@ -1,26 +0,0 @@ -package user - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/result" -) - -// Get user subcribe traffic logs -func GetUserSubscribeTrafficLogsHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - var req types.GetUserSubscribeTrafficLogsRequest - _ = c.BindQuery(&req) - validateErr := svcCtx.Validate(&req) - if validateErr != nil { - result.ParamErrorResult(c, validateErr) - return - } - - l := user.NewGetUserSubscribeTrafficLogsLogic(c.Request.Context(), svcCtx) - resp, err := l.GetUserSubscribeTrafficLogs(&req) - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/app/user/queryUserInfoHandler.go b/internal/handler/app/user/queryUserInfoHandler.go deleted file mode 100644 index 5d0087a..0000000 --- a/internal/handler/app/user/queryUserInfoHandler.go +++ /dev/null @@ -1,18 +0,0 @@ -package user - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/result" -) - -// query user info -func QueryUserInfoHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - - l := user.NewQueryUserInfoLogic(c.Request.Context(), svcCtx) - resp, err := l.QueryUserInfo() - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/app/user/queryuseraffiliatehandler.go b/internal/handler/app/user/queryuseraffiliatehandler.go deleted file mode 100644 index 26349c9..0000000 --- a/internal/handler/app/user/queryuseraffiliatehandler.go +++ /dev/null @@ -1,18 +0,0 @@ -package user - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/result" -) - -// Query User Affiliate Count -func QueryUserAffiliateHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - - l := user.NewQueryUserAffiliateLogic(c.Request.Context(), svcCtx) - resp, err := l.QueryUserAffiliate() - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/app/user/updatePasswordHandler.go b/internal/handler/app/user/updatePasswordHandler.go deleted file mode 100644 index dd40bcf..0000000 --- a/internal/handler/app/user/updatePasswordHandler.go +++ /dev/null @@ -1,26 +0,0 @@ -package user - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/result" -) - -// Update Password -func UpdatePasswordHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - var req types.UpdatePasswordRequeset - _ = c.ShouldBind(&req) - validateErr := svcCtx.Validate(&req) - if validateErr != nil { - result.ParamErrorResult(c, validateErr) - return - } - - l := user.NewUpdatePasswordLogic(c.Request.Context(), svcCtx) - err := l.UpdatePassword(&req) - result.HttpResult(c, nil, err) - } -} diff --git a/internal/handler/app/ws/appWsHandler.go b/internal/handler/app/ws/appWsHandler.go deleted file mode 100644 index 131c416..0000000 --- a/internal/handler/app/ws/appWsHandler.go +++ /dev/null @@ -1,20 +0,0 @@ -package ws - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/app/ws" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/result" -) - -// App heartbeat -func AppWsHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - ctx := c.Request.Context() - - // Logic: App heartbeat - l := ws.NewAppWsLogic(ctx, svcCtx) - err := l.AppWs(c.Writer, c.Request, c.Param("userid"), c.Param("identifier")) - result.HttpResult(c, nil, err) - } -} diff --git a/internal/handler/auth/telephoneUserRegisterHandler.go b/internal/handler/auth/telephoneUserRegisterHandler.go index 5388e2c..45a7ba8 100644 --- a/internal/handler/auth/telephoneUserRegisterHandler.go +++ b/internal/handler/auth/telephoneUserRegisterHandler.go @@ -25,6 +25,7 @@ func TelephoneUserRegisterHandler(svcCtx *svc.ServiceContext) func(c *gin.Contex } // get client ip req.IP = c.ClientIP() + req.UserAgent = c.Request.UserAgent() if svcCtx.Config.Verify.RegisterVerify { verifyTurns := turnstile.New(turnstile.Config{ Secret: svcCtx.Config.Verify.TurnstileSecret, diff --git a/internal/handler/auth/userRegisterHandler.go b/internal/handler/auth/userRegisterHandler.go index d7a2aec..ea40223 100644 --- a/internal/handler/auth/userRegisterHandler.go +++ b/internal/handler/auth/userRegisterHandler.go @@ -20,6 +20,7 @@ func UserRegisterHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { _ = c.ShouldBind(&req) // get client ip req.IP = c.ClientIP() + req.UserAgent = c.Request.UserAgent() if svcCtx.Config.Verify.RegisterVerify { verifyTurns := turnstile.New(turnstile.Config{ Secret: svcCtx.Config.Verify.TurnstileSecret, diff --git a/internal/handler/common/getApplicationHandler.go b/internal/handler/common/getApplicationHandler.go deleted file mode 100644 index 7a58ea1..0000000 --- a/internal/handler/common/getApplicationHandler.go +++ /dev/null @@ -1,18 +0,0 @@ -package common - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/common" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/result" -) - -// Get Tos Content -func GetApplicationHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - - l := common.NewGetApplicationLogic(c.Request.Context(), svcCtx) - resp, err := l.GetApplication() - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/common/getSubscriptionHandler.go b/internal/handler/common/getSubscriptionHandler.go deleted file mode 100644 index 94e98e4..0000000 --- a/internal/handler/common/getSubscriptionHandler.go +++ /dev/null @@ -1,18 +0,0 @@ -package common - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/common" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/result" -) - -// Get Subscription -func GetSubscriptionHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - - l := common.NewGetSubscriptionLogic(c.Request.Context(), svcCtx) - resp, err := l.GetSubscription() - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/notify/paymentNotifyHandler.go b/internal/handler/notify/paymentNotifyHandler.go index d2efcb1..cd7d8b9 100644 --- a/internal/handler/notify/paymentNotifyHandler.go +++ b/internal/handler/notify/paymentNotifyHandler.go @@ -26,7 +26,7 @@ func PaymentNotifyHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { } switch payment.ParsePlatform(platform) { - case payment.EPay: + case payment.EPay, payment.CryptoSaaS: req := &types.EPayNotifyRequest{} if err := c.ShouldBind(req); err != nil { result.HttpResult(c, nil, err) diff --git a/internal/handler/public/portal/getSubscriptionHandler.go b/internal/handler/public/portal/getSubscriptionHandler.go index 70c836d..6d7f735 100644 --- a/internal/handler/public/portal/getSubscriptionHandler.go +++ b/internal/handler/public/portal/getSubscriptionHandler.go @@ -4,14 +4,23 @@ import ( "github.com/gin-gonic/gin" "github.com/perfect-panel/server/internal/logic/public/portal" "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/result" ) // Get Subscription func GetSubscriptionHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { + var req types.GetSubscriptionRequest + _ = c.ShouldBind(&req) + validateErr := svcCtx.Validate(&req) + if validateErr != nil { + result.ParamErrorResult(c, validateErr) + return + } + l := portal.NewGetSubscriptionLogic(c.Request.Context(), svcCtx) - resp, err := l.GetSubscription() + resp, err := l.GetSubscription(&req) result.HttpResult(c, resp, err) } } diff --git a/internal/handler/public/portal/purchaseCheckoutHandler.go b/internal/handler/public/portal/purchaseCheckoutHandler.go index 21c6737..0e34d38 100644 --- a/internal/handler/public/portal/purchaseCheckoutHandler.go +++ b/internal/handler/public/portal/purchaseCheckoutHandler.go @@ -8,7 +8,7 @@ import ( "github.com/perfect-panel/server/pkg/result" ) -// Purchase Checkout +// PurchaseCheckoutHandler Purchase Checkout func PurchaseCheckoutHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { var req types.CheckoutOrderRequest diff --git a/internal/handler/public/subscribe/queryApplicationConfigHandler.go b/internal/handler/public/subscribe/queryApplicationConfigHandler.go deleted file mode 100644 index d9847f5..0000000 --- a/internal/handler/public/subscribe/queryApplicationConfigHandler.go +++ /dev/null @@ -1,18 +0,0 @@ -package subscribe - -import ( - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/logic/public/subscribe" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/result" -) - -// Get application config -func QueryApplicationConfigHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - - l := subscribe.NewQueryApplicationConfigLogic(c.Request.Context(), svcCtx) - resp, err := l.QueryApplicationConfig() - result.HttpResult(c, resp, err) - } -} diff --git a/internal/handler/public/subscribe/querySubscribeListHandler.go b/internal/handler/public/subscribe/querySubscribeListHandler.go index 309c75d..6a68a46 100644 --- a/internal/handler/public/subscribe/querySubscribeListHandler.go +++ b/internal/handler/public/subscribe/querySubscribeListHandler.go @@ -4,15 +4,23 @@ import ( "github.com/gin-gonic/gin" "github.com/perfect-panel/server/internal/logic/public/subscribe" "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/result" ) -// Get subscribe list +// QuerySubscribeListHandler Get subscribe list func QuerySubscribeListHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { + var req types.QuerySubscribeListRequest + _ = c.ShouldBind(&req) + validateErr := svcCtx.Validate(&req) + if validateErr != nil { + result.ParamErrorResult(c, validateErr) + return + } l := subscribe.NewQuerySubscribeListLogic(c.Request.Context(), svcCtx) - resp, err := l.QuerySubscribeList() + resp, err := l.QuerySubscribeList(&req) result.HttpResult(c, resp, err) } } diff --git a/internal/handler/routes.go b/internal/handler/routes.go index 606664e..860b885 100644 --- a/internal/handler/routes.go +++ b/internal/handler/routes.go @@ -22,15 +22,6 @@ import ( adminTicket "github.com/perfect-panel/server/internal/handler/admin/ticket" adminTool "github.com/perfect-panel/server/internal/handler/admin/tool" adminUser "github.com/perfect-panel/server/internal/handler/admin/user" - appAnnouncement "github.com/perfect-panel/server/internal/handler/app/announcement" - appAuth "github.com/perfect-panel/server/internal/handler/app/auth" - appDocument "github.com/perfect-panel/server/internal/handler/app/document" - appNode "github.com/perfect-panel/server/internal/handler/app/node" - appOrder "github.com/perfect-panel/server/internal/handler/app/order" - appPayment "github.com/perfect-panel/server/internal/handler/app/payment" - appSubscribe "github.com/perfect-panel/server/internal/handler/app/subscribe" - appUser "github.com/perfect-panel/server/internal/handler/app/user" - appWs "github.com/perfect-panel/server/internal/handler/app/ws" auth "github.com/perfect-panel/server/internal/handler/auth" authOauth "github.com/perfect-panel/server/internal/handler/auth/oauth" common "github.com/perfect-panel/server/internal/handler/common" @@ -198,8 +189,50 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) { adminLogGroupRouter.Use(middleware.AuthMiddleware(serverCtx)) { + // Filter balance log + adminLogGroupRouter.GET("/balance/list", adminLog.FilterBalanceLogHandler(serverCtx)) + + // Filter commission log + adminLogGroupRouter.GET("/commission/list", adminLog.FilterCommissionLogHandler(serverCtx)) + + // Filter email log + adminLogGroupRouter.GET("/email/list", adminLog.FilterEmailLogHandler(serverCtx)) + + // Filter gift log + adminLogGroupRouter.GET("/gift/list", adminLog.FilterGiftLogHandler(serverCtx)) + + // Filter login log + adminLogGroupRouter.GET("/login/list", adminLog.FilterLoginLogHandler(serverCtx)) + // Get message log list adminLogGroupRouter.GET("/message/list", adminLog.GetMessageLogListHandler(serverCtx)) + + // Filter mobile log + adminLogGroupRouter.GET("/mobile/list", adminLog.FilterMobileLogHandler(serverCtx)) + + // Filter register log + adminLogGroupRouter.GET("/register/list", adminLog.FilterRegisterLogHandler(serverCtx)) + + // Filter server traffic log + adminLogGroupRouter.GET("/server/traffic/list", adminLog.FilterServerTrafficLogHandler(serverCtx)) + + // Get log setting + adminLogGroupRouter.GET("/setting", adminLog.GetLogSettingHandler(serverCtx)) + + // Update log setting + adminLogGroupRouter.POST("/setting", adminLog.UpdateLogSettingHandler(serverCtx)) + + // Filter subscribe log + adminLogGroupRouter.GET("/subscribe/list", adminLog.FilterSubscribeLogHandler(serverCtx)) + + // Filter reset subscribe log + adminLogGroupRouter.GET("/subscribe/reset/list", adminLog.FilterResetSubscribeLogHandler(serverCtx)) + + // Filter user subscribe traffic log + adminLogGroupRouter.GET("/subscribe/traffic/list", adminLog.FilterUserSubscribeTrafficLogHandler(serverCtx)) + + // Filter traffic log details + adminLogGroupRouter.GET("/traffic/details", adminLog.FilterTrafficLogDetailsHandler(serverCtx)) } adminMarketingGroupRouter := router.Group("/v1/admin/marketing") @@ -220,6 +253,15 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) { // Stop a batch send email task adminMarketingGroupRouter.POST("/email/batch/stop", adminMarketing.StopBatchSendEmailTaskHandler(serverCtx)) + + // Create a quota task + adminMarketingGroupRouter.POST("/quota/create", adminMarketing.CreateQuotaTaskHandler(serverCtx)) + + // Query quota task list + adminMarketingGroupRouter.GET("/quota/list", adminMarketing.QueryQuotaTaskListHandler(serverCtx)) + + // Query quota task pre-count + adminMarketingGroupRouter.POST("/quota/pre-count", adminMarketing.QueryQuotaTaskPreCountHandler(serverCtx)) } adminOrderGroupRouter := router.Group("/v1/admin/order") @@ -260,56 +302,50 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) { adminServerGroupRouter.Use(middleware.AuthMiddleware(serverCtx)) { - // Update node - adminServerGroupRouter.PUT("/", adminServer.UpdateNodeHandler(serverCtx)) + // Create Server + adminServerGroupRouter.POST("/create", adminServer.CreateServerHandler(serverCtx)) - // Create node - adminServerGroupRouter.POST("/", adminServer.CreateNodeHandler(serverCtx)) + // Delete Server + adminServerGroupRouter.POST("/delete", adminServer.DeleteServerHandler(serverCtx)) - // Delete node - adminServerGroupRouter.DELETE("/", adminServer.DeleteNodeHandler(serverCtx)) + // Filter Server List + adminServerGroupRouter.GET("/list", adminServer.FilterServerListHandler(serverCtx)) - // Batch delete node - adminServerGroupRouter.DELETE("/batch", adminServer.BatchDeleteNodeHandler(serverCtx)) + // Check if there is any server or node to migrate + adminServerGroupRouter.GET("/migrate/has", adminServer.HasMigrateSeverNodeHandler(serverCtx)) - // Get node detail - adminServerGroupRouter.GET("/detail", adminServer.GetNodeDetailHandler(serverCtx)) + // Migrate server and node data to new database + adminServerGroupRouter.POST("/migrate/run", adminServer.MigrateServerNodeHandler(serverCtx)) - // Create node group - adminServerGroupRouter.POST("/group", adminServer.CreateNodeGroupHandler(serverCtx)) + // Create Node + adminServerGroupRouter.POST("/node/create", adminServer.CreateNodeHandler(serverCtx)) - // Update node group - adminServerGroupRouter.PUT("/group", adminServer.UpdateNodeGroupHandler(serverCtx)) + // Delete Node + adminServerGroupRouter.POST("/node/delete", adminServer.DeleteNodeHandler(serverCtx)) - // Delete node group - adminServerGroupRouter.DELETE("/group", adminServer.DeleteNodeGroupHandler(serverCtx)) + // Filter Node List + adminServerGroupRouter.GET("/node/list", adminServer.FilterNodeListHandler(serverCtx)) - // Batch delete node group - adminServerGroupRouter.DELETE("/group/batch", adminServer.BatchDeleteNodeGroupHandler(serverCtx)) + // Reset node sort + adminServerGroupRouter.POST("/node/sort", adminServer.ResetSortWithNodeHandler(serverCtx)) - // Get node group list - adminServerGroupRouter.GET("/group/list", adminServer.GetNodeGroupListHandler(serverCtx)) + // Toggle Node Status + adminServerGroupRouter.POST("/node/status/toggle", adminServer.ToggleNodeStatusHandler(serverCtx)) - // Get node list - adminServerGroupRouter.GET("/list", adminServer.GetNodeListHandler(serverCtx)) + // Query all node tags + adminServerGroupRouter.GET("/node/tags", adminServer.QueryNodeTagHandler(serverCtx)) - // Create rule group - adminServerGroupRouter.POST("/rule_group", adminServer.CreateRuleGroupHandler(serverCtx)) + // Update Node + adminServerGroupRouter.POST("/node/update", adminServer.UpdateNodeHandler(serverCtx)) - // Update rule group - adminServerGroupRouter.PUT("/rule_group", adminServer.UpdateRuleGroupHandler(serverCtx)) + // Get Server Protocols + adminServerGroupRouter.GET("/protocols", adminServer.GetServerProtocolsHandler(serverCtx)) - // Delete rule group - adminServerGroupRouter.DELETE("/rule_group", adminServer.DeleteRuleGroupHandler(serverCtx)) + // Reset server sort + adminServerGroupRouter.POST("/server/sort", adminServer.ResetSortWithServerHandler(serverCtx)) - // Get rule group list - adminServerGroupRouter.GET("/rule_group_list", adminServer.GetRuleGroupListHandler(serverCtx)) - - // Node sort - adminServerGroupRouter.POST("/sort", adminServer.NodeSortHandler(serverCtx)) - - // Get node tag list - adminServerGroupRouter.GET("/tag/list", adminServer.GetNodeTagListHandler(serverCtx)) + // Update Server + adminServerGroupRouter.POST("/update", adminServer.UpdateServerHandler(serverCtx)) } adminSubscribeGroupRouter := router.Group("/v1/admin/subscribe") @@ -357,33 +393,6 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) { adminSystemGroupRouter.Use(middleware.AuthMiddleware(serverCtx)) { - // Get application - adminSystemGroupRouter.GET("/application", adminSystem.GetApplicationHandler(serverCtx)) - - // Update application - adminSystemGroupRouter.PUT("/application", adminSystem.UpdateApplicationHandler(serverCtx)) - - // Create application - adminSystemGroupRouter.POST("/application", adminSystem.CreateApplicationHandler(serverCtx)) - - // Delete application - adminSystemGroupRouter.DELETE("/application", adminSystem.DeleteApplicationHandler(serverCtx)) - - // update application config - adminSystemGroupRouter.PUT("/application_config", adminSystem.UpdateApplicationConfigHandler(serverCtx)) - - // get application config - adminSystemGroupRouter.GET("/application_config", adminSystem.GetApplicationConfigHandler(serverCtx)) - - // Update application version - adminSystemGroupRouter.PUT("/application_version", adminSystem.UpdateApplicationVersionHandler(serverCtx)) - - // Create application version - adminSystemGroupRouter.POST("/application_version", adminSystem.CreateApplicationVersionHandler(serverCtx)) - - // Delete application - adminSystemGroupRouter.DELETE("/application_version", adminSystem.DeleteApplicationVersionHandler(serverCtx)) - // Get Currency Config adminSystemGroupRouter.GET("/currency_config", adminSystem.GetCurrencyConfigHandler(serverCtx)) @@ -435,9 +444,6 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) { // Update subscribe config adminSystemGroupRouter.PUT("/subscribe_config", adminSystem.UpdateSubscribeConfigHandler(serverCtx)) - // Get subscribe type - adminSystemGroupRouter.GET("/subscribe_type", adminSystem.GetSubscribeTypeHandler(serverCtx)) - // Get Team of Service Config adminSystemGroupRouter.GET("/tos_config", adminSystem.GetTosConfigHandler(serverCtx)) @@ -561,157 +567,13 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) { // Get user subcribe logs adminUserGroupRouter.GET("/subscribe/logs", adminUser.GetUserSubscribeLogsHandler(serverCtx)) + // Get user subcribe reset traffic logs + adminUserGroupRouter.GET("/subscribe/reset/logs", adminUser.GetUserSubscribeResetTrafficLogsHandler(serverCtx)) + // Get user subcribe traffic logs adminUserGroupRouter.GET("/subscribe/traffic_logs", adminUser.GetUserSubscribeTrafficLogsHandler(serverCtx)) } - appAnnouncementGroupRouter := router.Group("/v1/app/announcement") - appAnnouncementGroupRouter.Use(middleware.AppMiddleware(serverCtx), middleware.AuthMiddleware(serverCtx)) - - { - // Query announcement - appAnnouncementGroupRouter.GET("/list", appAnnouncement.QueryAnnouncementHandler(serverCtx)) - } - - appAuthGroupRouter := router.Group("/v1/app/auth") - appAuthGroupRouter.Use(middleware.AppMiddleware(serverCtx)) - - { - // Check Account - appAuthGroupRouter.POST("/check", appAuth.CheckHandler(serverCtx)) - - // GetAppConfig - appAuthGroupRouter.POST("/config", appAuth.GetAppConfigHandler(serverCtx)) - - // Login - appAuthGroupRouter.POST("/login", appAuth.LoginHandler(serverCtx)) - - // Register - appAuthGroupRouter.POST("/register", appAuth.RegisterHandler(serverCtx)) - - // Reset Password - appAuthGroupRouter.POST("/reset_password", appAuth.ResetPasswordHandler(serverCtx)) - } - - appDocumentGroupRouter := router.Group("/v1/app/document") - appDocumentGroupRouter.Use(middleware.AppMiddleware(serverCtx), middleware.AuthMiddleware(serverCtx)) - - { - // Get document detail - appDocumentGroupRouter.GET("/detail", appDocument.QueryDocumentDetailHandler(serverCtx)) - - // Get document list - appDocumentGroupRouter.GET("/list", appDocument.QueryDocumentListHandler(serverCtx)) - } - - appNodeGroupRouter := router.Group("/v1/app/node") - appNodeGroupRouter.Use(middleware.AppMiddleware(serverCtx), middleware.AuthMiddleware(serverCtx)) - - { - // Get Node list - appNodeGroupRouter.GET("/list", appNode.GetNodeListHandler(serverCtx)) - - // Get rule group list - appNodeGroupRouter.GET("/rule_group_list", appNode.GetRuleGroupListHandler(serverCtx)) - } - - appOrderGroupRouter := router.Group("/v1/app/order") - appOrderGroupRouter.Use(middleware.AppMiddleware(serverCtx), middleware.AuthMiddleware(serverCtx)) - - { - // Checkout order - appOrderGroupRouter.POST("/checkout", appOrder.CheckoutOrderHandler(serverCtx)) - - // Close order - appOrderGroupRouter.POST("/close", appOrder.CloseOrderHandler(serverCtx)) - - // Get order - appOrderGroupRouter.GET("/detail", appOrder.QueryOrderDetailHandler(serverCtx)) - - // Get order list - appOrderGroupRouter.GET("/list", appOrder.QueryOrderListHandler(serverCtx)) - - // Pre create order - appOrderGroupRouter.POST("/pre", appOrder.PreCreateOrderHandler(serverCtx)) - - // purchase Subscription - appOrderGroupRouter.POST("/purchase", appOrder.PurchaseHandler(serverCtx)) - - // Recharge - appOrderGroupRouter.POST("/recharge", appOrder.RechargeHandler(serverCtx)) - - // Renewal Subscription - appOrderGroupRouter.POST("/renewal", appOrder.RenewalHandler(serverCtx)) - - // Reset traffic - appOrderGroupRouter.POST("/reset", appOrder.ResetTrafficHandler(serverCtx)) - } - - appPaymentGroupRouter := router.Group("/v1/app/payment") - appPaymentGroupRouter.Use(middleware.AppMiddleware(serverCtx), middleware.AuthMiddleware(serverCtx)) - - { - // Get available payment methods - appPaymentGroupRouter.GET("/methods", appPayment.GetAvailablePaymentMethodsHandler(serverCtx)) - } - - appSubscribeGroupRouter := router.Group("/v1/app/subscribe") - appSubscribeGroupRouter.Use(middleware.AppMiddleware(serverCtx), middleware.AuthMiddleware(serverCtx)) - - { - // Get application config - appSubscribeGroupRouter.GET("/application/config", appSubscribe.QueryApplicationConfigHandler(serverCtx)) - - // Get subscribe group list - appSubscribeGroupRouter.GET("/group/list", appSubscribe.QuerySubscribeGroupListHandler(serverCtx)) - - // Get subscribe list - appSubscribeGroupRouter.GET("/list", appSubscribe.QuerySubscribeListHandler(serverCtx)) - - // Reset user subscription period - appSubscribeGroupRouter.POST("/reset/period", appSubscribe.ResetUserSubscribePeriodHandler(serverCtx)) - - // Get Already subscribed to package - appSubscribeGroupRouter.GET("/user/already_subscribe", appSubscribe.QueryUserAlreadySubscribeHandler(serverCtx)) - - // Get Available subscriptions for users - appSubscribeGroupRouter.GET("/user/available_subscribe", appSubscribe.QueryUserAvailableUserSubscribeHandler(serverCtx)) - } - - appUserGroupRouter := router.Group("/v1/app/user") - appUserGroupRouter.Use(middleware.AppMiddleware(serverCtx), middleware.AuthMiddleware(serverCtx)) - - { - // Delete Account - appUserGroupRouter.DELETE("/account", appUser.DeleteAccountHandler(serverCtx)) - - // Query User Affiliate Count - appUserGroupRouter.GET("/affiliate/count", appUser.QueryUserAffiliateHandler(serverCtx)) - - // Query User Affiliate List - appUserGroupRouter.GET("/affiliate/list", appUser.QueryUserAffiliateListHandler(serverCtx)) - - // query user info - appUserGroupRouter.GET("/info", appUser.QueryUserInfoHandler(serverCtx)) - - // Get user online time total - appUserGroupRouter.GET("/online_time/statistics", appUser.GetUserOnlineTimeStatisticsHandler(serverCtx)) - - // Update Password - appUserGroupRouter.PUT("/password", appUser.UpdatePasswordHandler(serverCtx)) - - // Get user subcribe traffic logs - appUserGroupRouter.GET("/subscribe/traffic_logs", appUser.GetUserSubscribeTrafficLogsHandler(serverCtx)) - } - - appWsGroupRouter := router.Group("/v1/app/ws") - appWsGroupRouter.Use(middleware.AuthMiddleware(serverCtx)) - - { - // App heartbeat - appWsGroupRouter.GET("/:userid/:identifier", appWs.AppWsHandler(serverCtx)) - } - authGroupRouter := router.Group("/v1/auth") { @@ -759,9 +621,6 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) { // Get Ads commonGroupRouter.GET("/ads", common.GetAdsHandler(serverCtx)) - // Get Tos Content - commonGroupRouter.GET("/application", common.GetApplicationHandler(serverCtx)) - // Check verification code commonGroupRouter.POST("/check_verification_code", common.CheckVerificationCodeHandler(serverCtx)) @@ -869,12 +728,6 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) { publicSubscribeGroupRouter.Use(middleware.AuthMiddleware(serverCtx)) { - // Get application config - publicSubscribeGroupRouter.GET("/application/config", publicSubscribe.QueryApplicationConfigHandler(serverCtx)) - - // Get subscribe group list - publicSubscribeGroupRouter.GET("/group/list", publicSubscribe.QuerySubscribeGroupListHandler(serverCtx)) - // Get subscribe list publicSubscribeGroupRouter.GET("/list", publicSubscribe.QuerySubscribeListHandler(serverCtx)) } @@ -989,4 +842,11 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) { // Get user list serverGroupRouter.GET("/user", server.GetServerUserListHandler(serverCtx)) } + + serverV2GroupRouter := router.Group("/v2/server") + + { + // Get Server Protocol Config + serverV2GroupRouter.GET("/:server_id", server.QueryServerProtocolConfigHandler(serverCtx)) + } } diff --git a/internal/handler/server/queryServerProtocolConfigHandler.go b/internal/handler/server/queryServerProtocolConfigHandler.go new file mode 100644 index 0000000..1514efa --- /dev/null +++ b/internal/handler/server/queryServerProtocolConfigHandler.go @@ -0,0 +1,41 @@ +package server + +import ( + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "github.com/perfect-panel/server/internal/logic/server" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/result" +) + +// QueryServerProtocolConfigHandler Get Server Protocol Config +func QueryServerProtocolConfigHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { + return func(c *gin.Context) { + var req types.QueryServerConfigRequest + + serverID, err := strconv.ParseInt(c.Param("server_id"), 10, 64) + if err != nil { + logger.Debugf("[QueryServerProtocolConfigHandler] - strconv.ParseInt(server_id) error: %v, Param: %s", err, c.Param("server_id")) + c.String(http.StatusBadRequest, "Invalid Params") + c.Abort() + return + } + req.ServerID = serverID + + key := c.GetHeader("secret_key") + if key == "" || key != svcCtx.Config.Node.NodeSecret { + logger.Debugf("[QueryServerProtocolConfigHandler] - secret_key error: %s", key) + c.String(http.StatusUnauthorized, "Unauthorized") + c.Abort() + return + } + + l := server.NewQueryServerProtocolConfigLogic(c.Request.Context(), svcCtx) + resp, err := l.QueryServerProtocolConfig(&req) + result.HttpResult(c, resp, err) + } +} diff --git a/internal/handler/subscribe.go b/internal/handler/subscribe.go index bf4cad8..d5cbf88 100644 --- a/internal/handler/subscribe.go +++ b/internal/handler/subscribe.go @@ -8,6 +8,8 @@ import ( "github.com/perfect-panel/server/internal/logic/subscribe" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/tool" ) func SubscribeHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { @@ -18,63 +20,50 @@ func SubscribeHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { } else { req.Token = c.Query("token") } + ua := c.GetHeader("User-Agent") req.UA = c.Request.Header.Get("User-Agent") req.Flag = c.Query("flag") - // intercept browser - ua := c.GetHeader("User-Agent") - if ua == "" { - c.String(http.StatusForbidden, "Access denied") - return - } - browserKeywords := []string{"chrome", "firefox", "safari", "edge", "opera", "micromessenger"} - for _, keyword := range browserKeywords { - lcUA := strings.ToLower(ua) - if strings.Contains(lcUA, keyword) { + if svcCtx.Config.Subscribe.UserAgentLimit { + if ua == "" { c.String(http.StatusForbidden, "Access denied") + c.Abort() + return + } + clientUserAgents := tool.RemoveDuplicateElements(strings.Split(svcCtx.Config.Subscribe.UserAgentList, "\n")...) + + // query client list + clients, err := svcCtx.ClientModel.List(c.Request.Context()) + if err != nil { + logger.Errorw("[PanDomainMiddleware] Query client list failed", logger.Field("error", err.Error())) + } + for _, item := range clients { + u := strings.ToLower(item.UserAgent) + u = strings.Trim(u, " ") + clientUserAgents = append(clientUserAgents, u) + } + + var allow = false + for _, keyword := range clientUserAgents { + keyword = strings.Trim(keyword, " ") + if keyword == "" { + continue + } + if strings.Contains(strings.ToLower(ua), strings.ToLower(keyword)) { + allow = true + } + } + if !allow { + c.String(http.StatusForbidden, "Access denied") + c.Abort() return } } l := subscribe.NewSubscribeLogic(c, svcCtx) - resp, err := l.Generate(&req) - if err != nil { - return - } - c.Header("subscription-userinfo", resp.Header) - c.String(200, "%s", string(resp.Config)) - } -} - -func V2SubscribeHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - var req types.SubscribeRequest - if c.Request.Header.Get("token") != "" { - req.Token = c.Request.Header.Get("token") - } else { - req.Token = c.Query("token") - } - req.UA = c.Request.Header.Get("User-Agent") - req.Flag = c.Query("flag") - - // intercept browser - ua := c.GetHeader("User-Agent") - if ua == "" { - c.String(http.StatusForbidden, "Access denied") - return - } - browserKeywords := []string{"chrome", "firefox", "safari", "edge", "opera", "micromessenger"} - for _, keyword := range browserKeywords { - lcUA := strings.ToLower(ua) - if strings.Contains(lcUA, keyword) { - c.String(http.StatusForbidden, "Access denied") - return - } - } - - l := subscribe.NewSubscribeLogic(c, svcCtx) - resp, err := l.V2(&req) + resp, err := l.Handler(&req) if err != nil { + c.String(http.StatusInternalServerError, "Internal Server") return } c.Header("subscription-userinfo", resp.Header) @@ -87,7 +76,5 @@ func RegisterSubscribeHandlers(router *gin.Engine, serverCtx *svc.ServiceContext if path == "" { path = "/api/subscribe" } - router.GET(path, V2SubscribeHandler(serverCtx)) - - router.GET(path+"/v2", V2SubscribeHandler(serverCtx)) + router.GET(path, SubscribeHandler(serverCtx)) } diff --git a/internal/logic/admin/application/previewSubscribeTemplateLogic.go b/internal/logic/admin/application/previewSubscribeTemplateLogic.go index 1781127..9bb197d 100644 --- a/internal/logic/admin/application/previewSubscribeTemplateLogic.go +++ b/internal/logic/admin/application/previewSubscribeTemplateLogic.go @@ -5,6 +5,7 @@ import ( "time" "github.com/perfect-panel/server/adapter" + "github.com/perfect-panel/server/internal/model/node" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" @@ -28,7 +29,11 @@ func NewPreviewSubscribeTemplateLogic(ctx context.Context, svcCtx *svc.ServiceCo } func (l *PreviewSubscribeTemplateLogic) PreviewSubscribeTemplate(req *types.PreviewSubscribeTemplateRequest) (resp *types.PreviewSubscribeTemplateResponse, err error) { - servers, err := l.svcCtx.ServerModel.FindAllServer(l.ctx) + _, servers, err := l.svcCtx.NodeModel.FilterNodeList(l.ctx, &node.FilterNodeParams{ + Page: 1, + Size: 1000, + Preload: true, + }) if err != nil { l.Errorf("[PreviewSubscribeTemplateLogic] FindAllServer error: %v", err.Error()) return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "FindAllServer error: %v", err.Error()) diff --git a/internal/logic/admin/console/queryServerTotalDataLogic.go b/internal/logic/admin/console/queryServerTotalDataLogic.go index ac7a5f8..5bdafca 100644 --- a/internal/logic/admin/console/queryServerTotalDataLogic.go +++ b/internal/logic/admin/console/queryServerTotalDataLogic.go @@ -6,12 +6,15 @@ import ( "strings" "time" - "github.com/perfect-panel/server/pkg/xerr" - + "github.com/perfect-panel/server/internal/model/log" + "github.com/perfect-panel/server/internal/model/node" + "github.com/perfect-panel/server/internal/model/traffic" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" "github.com/pkg/errors" + "gorm.io/gorm" ) type QueryServerTotalDataLogic struct { @@ -35,127 +38,194 @@ func (l *QueryServerTotalDataLogic) QueryServerTotalData() (resp *types.ServerTo return l.mockRevenueStatistics(), nil } - resp = &types.ServerTotalDataResponse{ - ServerTrafficRankingToday: make([]types.ServerTrafficData, 0), - ServerTrafficRankingYesterday: make([]types.ServerTrafficData, 0), - UserTrafficRankingToday: make([]types.UserTrafficData, 0), - UserTrafficRankingYesterday: make([]types.UserTrafficData, 0), + now := time.Now() + + todayStart := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) + todayEnd := todayStart.Add(24 * time.Hour).Add(-time.Second) + query := l.svcCtx.DB.WithContext(l.ctx) + var todayTop10User []log.UserTraffic + + err = query.Model(&traffic.TrafficLog{}). + Select("user_id, subscribe_id, SUM(download + upload) AS total, SUM(download) AS download, SUM(upload) AS upload"). + Where("timestamp BETWEEN ? AND ?", todayStart, todayEnd). + Group("user_id, subscribe_id"). + Order("total DESC"). + Limit(10). + Scan(&todayTop10User).Error + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + logger.Errorf("[Traffic Stat Queue] Query user traffic failed: %v", err.Error()) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), " Query user traffic failed: %v", err.Error()) + } + var userTodayTrafficRanking []types.UserTrafficData + for _, item := range todayTop10User { + userTodayTrafficRanking = append(userTodayTrafficRanking, types.UserTrafficData{ + SID: item.SubscribeId, + Upload: item.Upload, + Download: item.Download, + }) } - // Query node server status - servers, err := l.svcCtx.ServerModel.FindAllServer(l.ctx) - if err != nil { - l.Errorw("[QueryServerTotalDataLogic] FindAllServer error", logger.Field("error", err.Error())) - return nil, errors.Wrapf(err, "FindAllServer error: %v", err) - } - onlineServers, err := l.svcCtx.NodeCache.GetOnlineNodeStatusCount(l.ctx) - if err != nil { - l.Errorw("[QueryServerTotalDataLogic] GetOnlineNodeStatusCount error", logger.Field("error", err.Error())) - return nil, errors.Wrapf(err, "GetOnlineNodeStatusCount error: %v", err) - } - resp.OnlineServers = onlineServers - resp.OfflineServers = int64(len(servers) - int(onlineServers)) + // query yesterday user traffic rank log + yesterday := todayStart.Add(-24 * time.Hour).Format(time.DateOnly) - // 获取所有节点在线用户 - allNodeOnlineUser, err := l.svcCtx.NodeCache.GetAllNodeOnlineUser(l.ctx) - if err != nil { - l.Errorw("[QueryServerTotalDataLogic] Get all node online user failed", logger.Field("error", err.Error())) + var yesterdayLog log.SystemLog + err = query.Model(&log.SystemLog{}).Where("`date` = ? AND `type` = ?", yesterday, log.TypeUserTrafficRank).First(&yesterdayLog).Error + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + l.Errorw("[QueryServerTotalDataLogic] Query yesterday user traffic rank log error", logger.Field("error", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Query yesterday user traffic rank log error: %v", err) } - resp.OnlineUserIPs = int64(len(allNodeOnlineUser)) - // 获取所有节点今日上传下载流量 - allNodeUploadTraffic, err := l.svcCtx.NodeCache.GetAllNodeUploadTraffic(l.ctx) - if err != nil { - l.Errorw("[QueryServerTotalDataLogic] Get all node upload traffic failed", logger.Field("error", err.Error())) + var yesterdayUserRankData []types.UserTrafficData + if yesterdayLog.Id > 0 { + var rank log.UserTrafficRank + err = rank.Unmarshal([]byte(yesterdayLog.Content)) + if err != nil { + l.Errorw("[QueryServerTotalDataLogic] Unmarshal yesterday user traffic rank log error", logger.Field("error", err.Error())) + } + for _, v := range rank.Rank { + yesterdayUserRankData = append(yesterdayUserRankData, types.UserTrafficData{ + SID: v.SubscribeId, + Upload: v.Upload, + Download: v.Download, + }) + } } - resp.TodayUpload = allNodeUploadTraffic - allNodeDownloadTraffic, err := l.svcCtx.NodeCache.GetAllNodeDownloadTraffic(l.ctx) - if err != nil { - l.Errorw("[QueryServerTotalDataLogic] Get all node download traffic failed", logger.Field("error", err.Error())) + + // query server traffic rank today + var todayTop10Server []log.ServerTraffic + err = query.Model(&traffic.TrafficLog{}).Select("server_id, SUM(download + upload) AS total, SUM(download) AS download, SUM(upload) AS upload"). + Where("timestamp BETWEEN ? AND ?", todayStart, todayEnd). + Group("server_id"). + Order("total DESC"). + Limit(10). + Scan(&todayTop10Server).Error + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + logger.Errorf("[Traffic Stat Queue] Query server traffic failed: %v", err.Error()) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), " Query server traffic failed: %v", err.Error()) } - resp.TodayDownload = allNodeDownloadTraffic - // 获取节点流量排行榜 前10 - nodeTrafficRankingToday, err := l.svcCtx.NodeCache.GetNodeTodayTotalTrafficRank(l.ctx, 10) - if err != nil { - l.Errorw("[QueryServerTotalDataLogic] Get node today total traffic rank failed", logger.Field("error", err.Error())) + + var todayServerRanking []types.ServerTrafficData + for _, item := range todayTop10Server { + info, err := l.svcCtx.NodeModel.FindOneServer(l.ctx, item.ServerId) + if err != nil { + l.Errorw("[QueryServerTotalDataLogic] FindOneServer error", logger.Field("error", err.Error()), logger.Field("server_id", item.ServerId)) + continue + } + todayServerRanking = append(todayServerRanking, types.ServerTrafficData{ + ServerId: item.ServerId, + Name: info.Name, + Upload: item.Upload, + Download: item.Download, + }) } - if len(nodeTrafficRankingToday) > 0 { - var serverTrafficData []types.ServerTrafficData - for _, rank := range nodeTrafficRankingToday { - serverInfo, err := l.svcCtx.ServerModel.FindOne(l.ctx, rank.ID) + + // query server traffic rank yesterday + var yesterdayTop10Server []types.ServerTrafficData + var yesterdayServerTrafficLog log.SystemLog + err = query.Model(&log.SystemLog{}).Where("`date` = ? AND `type` = ?", yesterday, log.TypeServerTrafficRank).First(&yesterdayServerTrafficLog).Error + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + l.Errorw("[QueryServerTotalDataLogic] Query yesterday server traffic rank log error", logger.Field("error", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Query yesterday server traffic rank log error: %v", err) + } + if yesterdayServerTrafficLog.Id > 0 { + var rank log.ServerTrafficRank + err = rank.Unmarshal([]byte(yesterdayServerTrafficLog.Content)) + if err != nil { + l.Errorw("[QueryServerTotalDataLogic] Unmarshal yesterday server traffic rank log error", logger.Field("error", err.Error())) + } + + for _, v := range rank.Rank { + info, err := l.svcCtx.NodeModel.FindOneServer(l.ctx, v.ServerId) if err != nil { - l.Errorw("[QueryServerTotalDataLogic] FindOne error", logger.Field("error", err)) + l.Errorw("[QueryServerTotalDataLogic] FindOneServer error", logger.Field("error", err.Error()), logger.Field("server_id", v.ServerId)) continue } - serverTrafficData = append(serverTrafficData, types.ServerTrafficData{ - ServerId: rank.ID, - Name: serverInfo.Name, - Upload: rank.Upload, - Download: rank.Download, + yesterdayTop10Server = append(yesterdayTop10Server, types.ServerTrafficData{ + ServerId: v.ServerId, + Name: info.Name, + Upload: v.Upload, + Download: v.Download, }) } - resp.ServerTrafficRankingToday = serverTrafficData - } - // 获取用户流量排行榜 前10 - userTrafficRankingToday, err := l.svcCtx.NodeCache.GetUserTodayTotalTrafficRank(l.ctx, 10) - if err != nil { - l.Errorw("[QueryServerTotalDataLogic] Get user today total traffic rank failed", logger.Field("error", err.Error())) } - if len(userTrafficRankingToday) > 0 { - var userTrafficData []types.UserTrafficData - for _, rank := range userTrafficRankingToday { - userTrafficData = append(userTrafficData, types.UserTrafficData{ - SID: rank.SID, - Upload: rank.Upload, - Download: rank.Download, - }) - } - resp.UserTrafficRankingToday = userTrafficData - } - // 获取昨日节点流量排行榜 前10 - nodeTrafficRankingYesterday, err := l.svcCtx.NodeCache.GetYesterdayNodeTotalTrafficRank(l.ctx) + // query online user count + onlineUsers, err := l.svcCtx.NodeModel.OnlineUserSubscribeGlobal(l.ctx) if err != nil { - l.Errorw("[QueryServerTotalDataLogic] Get yesterday node total traffic rank failed", logger.Field("error", err.Error())) - } - if len(nodeTrafficRankingYesterday) > 0 { - var serverTrafficData []types.ServerTrafficData - for _, rank := range nodeTrafficRankingYesterday { - serverTrafficData = append(serverTrafficData, types.ServerTrafficData{ - ServerId: rank.ID, - Name: rank.Name, - Upload: rank.Upload, - Download: rank.Download, - }) - } - resp.ServerTrafficRankingYesterday = serverTrafficData - } - // 获取昨日用户流量排行榜 前10 - userTrafficRankingYesterday, err := l.svcCtx.NodeCache.GetYesterdayUserTotalTrafficRank(l.ctx) - if err != nil { - l.Errorw("[QueryServerTotalDataLogic] Get yesterday user total traffic rank failed", logger.Field("error", err.Error())) - } - if len(userTrafficRankingYesterday) > 0 { - var userTrafficData []types.UserTrafficData - for _, rank := range userTrafficRankingYesterday { - userTrafficData = append(userTrafficData, types.UserTrafficData{ - SID: rank.SID, - Upload: rank.Upload, - Download: rank.Download, - }) - } - resp.UserTrafficRankingYesterday = userTrafficData + l.Errorw("[QueryServerTotalDataLogic] OnlineUserSubscribeGlobal error", logger.Field("error", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "OnlineUserSubscribeGlobal error: %v", err) } - // Query node traffic by monthly - nodeTraffic, err := l.svcCtx.TrafficLogModel.QueryTrafficByMonthly(l.ctx, time.Now()) - - if err != nil { - l.Errorw("[QueryServerTotalDataLogic] QueryTrafficByMonthly error", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "QueryTrafficByMonthly error: %v", err.Error()) + // query online/offline server count + var onlineServers, offlineServers int64 + err = query.Model(&node.Server{}).Where("`last_reported_at` > ?", now.Add(-5*time.Minute)).Count(&onlineServers).Error + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + l.Errorw("[QueryServerTotalDataLogic] Count online servers error", logger.Field("error", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Count online servers error: %v", err) + } + + err = query.Model(&node.Server{}).Where("`last_reported_at` <= ? OR `last_reported_at` IS NULL", now.Add(-5*time.Minute)).Count(&offlineServers).Error + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + l.Errorw("[QueryServerTotalDataLogic] Count offline servers error", logger.Field("error", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Count offline servers error: %v", err) + } + // TodayUpload, TodayDownload, MonthlyUpload, MonthlyDownload + var todayUpload, todayDownload, monthlyUpload, monthlyDownload int64 + + type trafficSum struct { + Upload int64 + Download int64 + } + var todayTraffic trafficSum + // Today + err = query.Model(&traffic.TrafficLog{}).Select("SUM(upload) AS upload, SUM(download) AS download"). + Where("timestamp BETWEEN ? AND ?", todayStart, todayEnd). + Scan(&todayTraffic).Error + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + l.Errorw("[QueryServerTotalDataLogic] Sum today traffic error", logger.Field("error", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Sum today traffic error: %v", err) + } + todayUpload = todayTraffic.Upload + todayDownload = todayTraffic.Download + + // Monthly + monthlyUpload += todayUpload + monthlyDownload += todayDownload + + for i := now.Day() - 1; i >= 1; i-- { + var logInfo log.SystemLog + date := time.Date(now.Year(), now.Month(), i, 0, 0, 0, 0, now.Location()).Format(time.DateOnly) + err = query.Model(&log.SystemLog{}).Where("`date` = ? AND `type` = ?", date, log.TypeTrafficStat).First(&logInfo).Error + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + l.Errorw("[QueryServerTotalDataLogic] Query daily traffic stat log error", logger.Field("error", err.Error()), logger.Field("date", date)) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Query daily traffic stat log error: %v", err) + } + if logInfo.Id > 0 { + var stat log.TrafficStat + err = stat.Unmarshal([]byte(logInfo.Content)) + if err != nil { + l.Errorw("[QueryServerTotalDataLogic] Unmarshal daily traffic stat log error", logger.Field("error", err.Error()), logger.Field("date", date)) + continue + } + monthlyUpload += stat.Upload + monthlyDownload += stat.Download + } + } + + resp = &types.ServerTotalDataResponse{ + OnlineUsers: onlineUsers, + OnlineServers: onlineServers, + OfflineServers: offlineServers, + TodayUpload: todayUpload, + TodayDownload: todayDownload, + MonthlyUpload: monthlyUpload, + MonthlyDownload: monthlyDownload, + UpdatedAt: now.Unix(), + ServerTrafficRankingToday: todayServerRanking, + ServerTrafficRankingYesterday: yesterdayTop10Server, + UserTrafficRankingToday: userTodayTrafficRanking, + UserTrafficRankingYesterday: yesterdayUserRankData, } - resp.MonthlyUpload = nodeTraffic.Upload - resp.MonthlyDownload = nodeTraffic.Download return resp, nil } @@ -215,7 +285,7 @@ func (l *QueryServerTotalDataLogic) mockRevenueStatistics() *types.ServerTotalDa //} // return &types.ServerTotalDataResponse{ - OnlineUserIPs: 1688, + OnlineUsers: 1688, OnlineServers: 8, OfflineServers: 2, TodayUpload: 8888888888, // ~8.3GB diff --git a/internal/logic/admin/log/filterBalanceLogLogic.go b/internal/logic/admin/log/filterBalanceLogLogic.go new file mode 100644 index 0000000..6393d66 --- /dev/null +++ b/internal/logic/admin/log/filterBalanceLogLogic.go @@ -0,0 +1,64 @@ +package log + +import ( + "context" + + "github.com/perfect-panel/server/internal/model/log" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" +) + +type FilterBalanceLogLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// NewFilterBalanceLogLogic Filter balance log +func NewFilterBalanceLogLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FilterBalanceLogLogic { + return &FilterBalanceLogLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *FilterBalanceLogLogic) FilterBalanceLog(req *types.FilterBalanceLogRequest) (resp *types.FilterBalanceLogResponse, err error) { + data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: req.Page, + Size: req.Size, + Type: log.TypeBalance.Uint8(), + Data: req.Date, + ObjectID: req.UserId, + }) + + if err != nil { + l.Errorw("[FilterBalanceLog] Query User Balance Log Error:", logger.Field("error", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Query User Balance Log Error") + } + + list := make([]types.BalanceLog, 0) + for _, datum := range data { + var content log.Balance + if err = content.Unmarshal([]byte(datum.Content)); err != nil { + l.Errorf("[QueryUserBalanceLog] unmarshal balance log content failed: %v", err.Error()) + continue + } + list = append(list, types.BalanceLog{ + UserId: datum.ObjectID, + Amount: content.Amount, + Type: content.Type, + OrderNo: content.OrderNo, + Balance: content.Balance, + Timestamp: content.Timestamp, + }) + } + + return &types.FilterBalanceLogResponse{ + Total: total, + List: list, + }, nil +} diff --git a/internal/logic/admin/log/filterCommissionLogLogic.go b/internal/logic/admin/log/filterCommissionLogLogic.go new file mode 100644 index 0000000..6e4020d --- /dev/null +++ b/internal/logic/admin/log/filterCommissionLogLogic.go @@ -0,0 +1,61 @@ +package log + +import ( + "context" + + "github.com/perfect-panel/server/internal/model/log" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" +) + +type FilterCommissionLogLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// NewFilterCommissionLogLogic Filter commission log +func NewFilterCommissionLogLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FilterCommissionLogLogic { + return &FilterCommissionLogLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *FilterCommissionLogLogic) FilterCommissionLog(req *types.FilterCommissionLogRequest) (resp *types.FilterCommissionLogResponse, err error) { + data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: req.Page, + Size: req.Size, + Data: req.Date, + Type: log.TypeCommission.Uint8(), + ObjectID: req.UserId, + }) + if err != nil { + l.Errorw("Query User Commission Log failed", logger.Field("error", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Query User Commission Log failed") + } + var list []types.CommissionLog + + for _, datum := range data { + var content log.Commission + if err = content.Unmarshal([]byte(datum.Content)); err != nil { + l.Errorf("unmarshal commission log content failed: %v", err.Error()) + continue + } + list = append(list, types.CommissionLog{ + UserId: datum.ObjectID, + Type: content.Type, + Amount: content.Amount, + OrderNo: content.OrderNo, + Timestamp: content.Timestamp, + }) + } + return &types.FilterCommissionLogResponse{ + Total: total, + List: list, + }, nil +} diff --git a/internal/logic/admin/log/filterEmailLogLogic.go b/internal/logic/admin/log/filterEmailLogLogic.go new file mode 100644 index 0000000..21ce204 --- /dev/null +++ b/internal/logic/admin/log/filterEmailLogLogic.go @@ -0,0 +1,68 @@ +package log + +import ( + "context" + + "github.com/perfect-panel/server/internal/model/log" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" +) + +type FilterEmailLogLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// NewFilterEmailLogLogic Filter email log +func NewFilterEmailLogLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FilterEmailLogLogic { + return &FilterEmailLogLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *FilterEmailLogLogic) FilterEmailLog(req *types.FilterLogParams) (resp *types.FilterEmailLogResponse, err error) { + data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: req.Page, + Size: req.Size, + Type: log.TypeEmailMessage.Uint8(), + Data: req.Date, + Search: req.Search, + }) + + if err != nil { + l.Errorf("[FilterEmailLog] failed to filter system log: %v", err.Error()) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "failed to filter system log: %v", err.Error()) + } + + var list []types.MessageLog + + for _, datum := range data { + var content log.Message + err = content.Unmarshal([]byte(datum.Content)) + if err != nil { + l.Errorf("[FilterEmailLog] failed to unmarshal content: %v", err.Error()) + continue + } + list = append(list, types.MessageLog{ + Id: datum.Id, + Type: datum.Type, + Platform: content.Platform, + To: content.To, + Subject: content.Subject, + Content: content.Content, + Status: content.Status, + CreatedAt: datum.CreatedAt.UnixMilli(), + }) + } + + return &types.FilterEmailLogResponse{ + Total: total, + List: list, + }, nil +} diff --git a/internal/logic/admin/log/filterGiftLogLogic.go b/internal/logic/admin/log/filterGiftLogLogic.go new file mode 100644 index 0000000..5b23119 --- /dev/null +++ b/internal/logic/admin/log/filterGiftLogLogic.go @@ -0,0 +1,68 @@ +package log + +import ( + "context" + + "github.com/perfect-panel/server/internal/model/log" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" +) + +type FilterGiftLogLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// Filter gift log +func NewFilterGiftLogLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FilterGiftLogLogic { + return &FilterGiftLogLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *FilterGiftLogLogic) FilterGiftLog(req *types.FilterGiftLogRequest) (resp *types.FilterGiftLogResponse, err error) { + data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: req.Page, + Size: req.Size, + Type: log.TypeGift.Uint8(), + ObjectID: req.UserId, + Data: req.Date, + Search: req.Search, + }) + + if err != nil { + l.Errorf("[FilterGiftLog] failed to filter system log: %v", err.Error()) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "failed to filter system log: %v", err.Error()) + } + + var list []types.GiftLog + for _, datum := range data { + var content log.Gift + err = content.Unmarshal([]byte(datum.Content)) + if err != nil { + l.Errorf("[FilterGiftLog] failed to unmarshal content: %v", err.Error()) + continue + } + list = append(list, types.GiftLog{ + Type: content.Type, + UserId: datum.ObjectID, + OrderNo: content.OrderNo, + SubscribeId: content.SubscribeId, + Amount: content.Amount, + Balance: content.Balance, + Remark: content.Remark, + Timestamp: content.Timestamp, + }) + } + + return &types.FilterGiftLogResponse{ + Total: total, + List: list, + }, nil +} diff --git a/internal/logic/admin/log/filterLoginLogLogic.go b/internal/logic/admin/log/filterLoginLogLogic.go new file mode 100644 index 0000000..3a43941 --- /dev/null +++ b/internal/logic/admin/log/filterLoginLogLogic.go @@ -0,0 +1,65 @@ +package log + +import ( + "context" + + "github.com/perfect-panel/server/internal/model/log" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" +) + +type FilterLoginLogLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// NewFilterLoginLogLogic Filter login log +func NewFilterLoginLogLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FilterLoginLogLogic { + return &FilterLoginLogLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *FilterLoginLogLogic) FilterLoginLog(req *types.FilterLoginLogRequest) (resp *types.FilterLoginLogResponse, err error) { + data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: req.Page, + Size: req.Size, + Type: log.TypeLogin.Uint8(), + ObjectID: req.UserId, + Data: req.Date, + Search: req.Search, + }) + + if err != nil { + l.Errorf("[FilterLoginLog] failed to filter system log: %v", err.Error()) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "failed to filter system log: %v", err.Error()) + } + var list []types.LoginLog + for _, datum := range data { + var item log.Login + err = item.Unmarshal([]byte(datum.Content)) + if err != nil { + l.Errorf("[FilterLoginLog] failed to unmarshal content: %v", err.Error()) + continue + } + list = append(list, types.LoginLog{ + UserId: datum.ObjectID, + Method: item.Method, + LoginIP: item.LoginIP, + UserAgent: item.UserAgent, + Success: item.Success, + Timestamp: datum.CreatedAt.UnixMilli(), + }) + } + + return &types.FilterLoginLogResponse{ + Total: total, + List: list, + }, nil +} diff --git a/internal/logic/admin/log/filterMobileLogLogic.go b/internal/logic/admin/log/filterMobileLogLogic.go new file mode 100644 index 0000000..f5f0f4c --- /dev/null +++ b/internal/logic/admin/log/filterMobileLogLogic.go @@ -0,0 +1,68 @@ +package log + +import ( + "context" + + "github.com/perfect-panel/server/internal/model/log" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" +) + +type FilterMobileLogLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// Filter mobile log +func NewFilterMobileLogLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FilterMobileLogLogic { + return &FilterMobileLogLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *FilterMobileLogLogic) FilterMobileLog(req *types.FilterLogParams) (resp *types.FilterMobileLogResponse, err error) { + data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: req.Page, + Size: req.Size, + Type: log.TypeMobileMessage.Uint8(), + Data: req.Date, + Search: req.Search, + }) + + if err != nil { + l.Errorf("[FilterMobileLog] failed to filter system log: %v", err.Error()) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "failed to filter system log: %v", err.Error()) + } + + var list []types.MessageLog + + for _, datum := range data { + var content log.Message + err = content.Unmarshal([]byte(datum.Content)) + if err != nil { + l.Errorf("[FilterMobileLog] failed to unmarshal content: %v", err.Error()) + continue + } + list = append(list, types.MessageLog{ + Id: datum.Id, + Type: datum.Type, + Platform: content.Platform, + To: content.To, + Subject: content.Subject, + Content: content.Content, + Status: content.Status, + CreatedAt: datum.CreatedAt.UnixMilli(), + }) + } + + return &types.FilterMobileLogResponse{ + Total: total, + List: list, + }, nil +} diff --git a/internal/logic/admin/log/filterRegisterLogLogic.go b/internal/logic/admin/log/filterRegisterLogLogic.go new file mode 100644 index 0000000..81c9684 --- /dev/null +++ b/internal/logic/admin/log/filterRegisterLogLogic.go @@ -0,0 +1,66 @@ +package log + +import ( + "context" + + "github.com/perfect-panel/server/internal/model/log" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" +) + +type FilterRegisterLogLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// Filter register log +func NewFilterRegisterLogLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FilterRegisterLogLogic { + return &FilterRegisterLogLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *FilterRegisterLogLogic) FilterRegisterLog(req *types.FilterRegisterLogRequest) (resp *types.FilterRegisterLogResponse, err error) { + data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: req.Page, + Size: req.Size, + Type: log.TypeRegister.Uint8(), + ObjectID: req.UserId, + Data: req.Date, + Search: req.Search, + }) + + if err != nil { + l.Errorf("[FilterRegisterLog] failed to filter system log: %v", err.Error()) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "failed to filter system log: %v", err.Error()) + } + + var list []types.RegisterLog + for _, datum := range data { + var item log.Register + err = item.Unmarshal([]byte(datum.Content)) + if err != nil { + l.Errorf("[FilterLoginLog] failed to unmarshal content: %v", err.Error()) + continue + } + list = append(list, types.RegisterLog{ + UserId: datum.ObjectID, + AuthMethod: item.AuthMethod, + Identifier: item.Identifier, + RegisterIP: item.RegisterIP, + UserAgent: item.UserAgent, + Timestamp: item.Timestamp, + }) + } + + return &types.FilterRegisterLogResponse{ + List: list, + Total: total, + }, nil +} diff --git a/internal/logic/admin/log/filterResetSubscribeLogLogic.go b/internal/logic/admin/log/filterResetSubscribeLogLogic.go new file mode 100644 index 0000000..31e2d2a --- /dev/null +++ b/internal/logic/admin/log/filterResetSubscribeLogLogic.go @@ -0,0 +1,66 @@ +package log + +import ( + "context" + + "github.com/perfect-panel/server/internal/model/log" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" +) + +type FilterResetSubscribeLogLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// NewFilterResetSubscribeLogLogic Filter reset subscribe log +func NewFilterResetSubscribeLogLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FilterResetSubscribeLogLogic { + return &FilterResetSubscribeLogLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *FilterResetSubscribeLogLogic) FilterResetSubscribeLog(req *types.FilterResetSubscribeLogRequest) (resp *types.FilterResetSubscribeLogResponse, err error) { + data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: req.Page, + Size: req.Size, + Type: log.TypeResetSubscribe.Uint8(), + ObjectID: req.UserSubscribeId, + Data: req.Date, + Search: req.Search, + }) + + if err != nil { + l.Errorf("[FilterResetSubscribeLog] failed to filter system log: %v", err.Error()) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "failed to filter system log: %v", err.Error()) + } + + var list []types.ResetSubscribeLog + + for _, item := range data { + var content log.ResetSubscribe + err = content.Unmarshal([]byte(item.Content)) + if err != nil { + l.Errorf("[FilterResetSubscribeLog] failed to unmarshal content: %v", err.Error()) + continue + } + list = append(list, types.ResetSubscribeLog{ + Type: content.Type, + UserId: content.UserId, + UserSubscribeId: item.ObjectID, + OrderNo: content.OrderNo, + Timestamp: content.Timestamp, + }) + } + + return &types.FilterResetSubscribeLogResponse{ + List: list, + Total: total, + }, nil +} diff --git a/internal/logic/admin/log/filterServerTrafficLogLogic.go b/internal/logic/admin/log/filterServerTrafficLogLogic.go new file mode 100644 index 0000000..df5ce41 --- /dev/null +++ b/internal/logic/admin/log/filterServerTrafficLogLogic.go @@ -0,0 +1,166 @@ +package log + +import ( + "context" + "time" + + "github.com/perfect-panel/server/internal/model/log" + "github.com/perfect-panel/server/internal/model/traffic" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" +) + +type FilterServerTrafficLogLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// NewFilterServerTrafficLogLogic Filter server traffic log +func NewFilterServerTrafficLogLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FilterServerTrafficLogLogic { + return &FilterServerTrafficLogLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} +func (l *FilterServerTrafficLogLogic) FilterServerTrafficLog(req *types.FilterServerTrafficLogRequest) (resp *types.FilterServerTrafficLogResponse, err error) { + today := time.Now().Format("2006-01-02") + var list []types.ServerTrafficLog + var total int64 + + if req.Date == today || req.Date == "" { + now := time.Now() + start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local) + end := start.Add(24 * time.Hour).Add(-time.Nanosecond) + + var serverTraffic []log.ServerTraffic + err = l.svcCtx.DB.WithContext(l.ctx). + Model(&traffic.TrafficLog{}). + Select("server_id, SUM(download + upload) AS total, SUM(download) AS download, SUM(upload) AS upload"). + Where("timestamp BETWEEN ? AND ?", start, end). + Group("server_id"). + Order("SUM(download + upload) DESC"). + Scan(&serverTraffic).Error + if err != nil { + l.Errorw("[FilterServerTrafficLog] Query Database Error", logger.Field("error", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "today traffic query error: %s", err.Error()) + } + + for _, v := range serverTraffic { + list = append(list, types.ServerTrafficLog{ + ServerId: v.ServerId, + Upload: v.Upload, + Download: v.Download, + Total: v.Total, + Date: today, + Details: true, + }) + } + + todayTotal := len(list) + + startIdx := (req.Page - 1) * req.Size + endIdx := startIdx + req.Size + + if startIdx < todayTotal { + if endIdx > todayTotal { + endIdx = todayTotal + } + pageData := list[startIdx:endIdx] + return &types.FilterServerTrafficLogResponse{ + List: pageData, + Total: int64(todayTotal), + }, nil + } + + need := endIdx - todayTotal + historyPage := (need + req.Size - 1) / req.Size // 算出需要的历史页数 + historyData, historyTotal, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: historyPage, + Size: need, + Type: log.TypeServerTraffic.Uint8(), + }) + if err != nil { + l.Errorw("[FilterServerTrafficLog] Query History Error", logger.Field("error", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "history query error: %s", err.Error()) + } + + for _, item := range historyData { + var content log.ServerTraffic + if err = content.Unmarshal([]byte(item.Content)); err != nil { + l.Errorw("[FilterServerTrafficLog] Unmarshal Error", logger.Field("error", err.Error()), logger.Field("content", item.Content)) + continue + } + + hasDetails := true + if l.svcCtx.Config.Log.AutoClear { + last := now.AddDate(0, 0, int(-l.svcCtx.Config.Log.ClearDays)) + dataTime, err := time.Parse(time.DateOnly, item.Date) + if err != nil { + l.Errorw("[FilterServerTrafficLog] Parse Date Error", logger.Field("error", err.Error()), logger.Field("date", item.Date)) + } else { + if dataTime.Before(last) { + hasDetails = false + } else { + hasDetails = true + } + } + } + + list = append(list, types.ServerTrafficLog{ + ServerId: item.ObjectID, + Upload: content.Upload, + Download: content.Download, + Total: content.Total, + Date: item.Date, + Details: hasDetails, + }) + } + + // 返回最终分页数据 + if endIdx > len(list) { + endIdx = len(list) + } + pageData := list[startIdx:endIdx] + + return &types.FilterServerTrafficLogResponse{ + List: pageData, + Total: int64(todayTotal) + historyTotal, + }, nil + } + + data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: req.Page, + Size: req.Size, + Type: log.TypeServerTraffic.Uint8(), + }) + if err != nil { + l.Errorw("[FilterServerTrafficLog] Query Database Error", logger.Field("error", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "history query error: %s", err.Error()) + } + + for _, item := range data { + var content log.ServerTraffic + if err = content.Unmarshal([]byte(item.Content)); err != nil { + l.Errorw("[FilterServerTrafficLog] Unmarshal Error", logger.Field("error", err.Error()), logger.Field("content", item.Content)) + continue + } + list = append(list, types.ServerTrafficLog{ + ServerId: item.ObjectID, + Upload: content.Upload, + Download: content.Download, + Total: content.Total, + Date: item.Date, + Details: false, + }) + } + + return &types.FilterServerTrafficLogResponse{ + List: list, + Total: total, + }, nil +} diff --git a/internal/logic/admin/log/filterSubscribeLogLogic.go b/internal/logic/admin/log/filterSubscribeLogLogic.go new file mode 100644 index 0000000..560b145 --- /dev/null +++ b/internal/logic/admin/log/filterSubscribeLogLogic.go @@ -0,0 +1,71 @@ +package log + +import ( + "context" + "strconv" + + "github.com/perfect-panel/server/internal/model/log" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" +) + +type FilterSubscribeLogLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// NewFilterSubscribeLogLogic Filter subscribe log +func NewFilterSubscribeLogLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FilterSubscribeLogLogic { + return &FilterSubscribeLogLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *FilterSubscribeLogLogic) FilterSubscribeLog(req *types.FilterSubscribeLogRequest) (resp *types.FilterSubscribeLogResponse, err error) { + params := &log.FilterParams{ + Page: req.Page, + Size: req.Size, + Type: log.TypeSubscribe.Uint8(), + Data: req.Date, + ObjectID: req.UserId, + } + + if req.UserSubscribeId != 0 { + params.Search = `"user_subscribe_id":` + strconv.FormatInt(req.UserSubscribeId, 10) + } + + data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, params) + if err != nil { + l.Errorf("[FilterSubscribeLog] failed to filter system log: %v", err.Error()) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "failed to filter system log") + } + + var list []types.SubscribeLog + for _, datum := range data { + var content log.Subscribe + err = content.Unmarshal([]byte(datum.Content)) + if err != nil { + l.Errorf("[FilterSubscribeLog] failed to unmarshal content: %v", err.Error()) + continue + } + list = append(list, types.SubscribeLog{ + UserId: datum.ObjectID, + Token: content.Token, + UserAgent: content.UserAgent, + ClientIP: content.ClientIP, + UserSubscribeId: content.UserSubscribeId, + Timestamp: datum.CreatedAt.UnixMilli(), + }) + } + + return &types.FilterSubscribeLogResponse{ + Total: total, + List: list, + }, nil +} diff --git a/internal/logic/admin/log/filterTrafficLogDetailsLogic.go b/internal/logic/admin/log/filterTrafficLogDetailsLogic.go new file mode 100644 index 0000000..0dea661 --- /dev/null +++ b/internal/logic/admin/log/filterTrafficLogDetailsLogic.go @@ -0,0 +1,84 @@ +package log + +import ( + "context" + "time" + + "github.com/perfect-panel/server/internal/model/traffic" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" +) + +type FilterTrafficLogDetailsLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// NewFilterTrafficLogDetailsLogic Filter traffic log details +func NewFilterTrafficLogDetailsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FilterTrafficLogDetailsLogic { + return &FilterTrafficLogDetailsLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *FilterTrafficLogDetailsLogic) FilterTrafficLogDetails(req *types.FilterTrafficLogDetailsRequest) (resp *types.FilterTrafficLogDetailsResponse, err error) { + var start, end time.Time + if req.Date != "" { + day, err := time.ParseInLocation("2006-01-02", req.Date, time.Local) + if err != nil { + l.Errorw("[FilterTrafficLogDetails] Date Parse Error", logger.Field("error", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), " date parse error: %s", err.Error()) + } + start = day + end = day.Add(24*time.Hour - time.Nanosecond) + } else { + // query today + now := time.Now() + start = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) + end = start.Add(24*time.Hour - time.Nanosecond) + } + var data []*traffic.TrafficLog + tx := l.svcCtx.DB.WithContext(l.ctx).Model(&traffic.TrafficLog{}) + if req.ServerId != 0 { + tx = tx.Where("server_id = ?", req.ServerId) + } + if !start.IsZero() && !end.IsZero() { + tx = tx.Where("timestamp BETWEEN ? AND ?", start, end) + } + if req.UserId != 0 { + tx = tx.Where("user_id = ?", req.UserId) + } + if req.SubscribeId != 0 { + tx = tx.Where("subscribe_id = ?", req.SubscribeId) + } + var total int64 + err = tx.Count(&total).Limit(req.Size).Offset((req.Page - 1) * req.Size).Find(&data).Error + if err != nil { + l.Errorw("[FilterTrafficLogDetails] Query Database Error", logger.Field("error", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), " database query error: %s", err.Error()) + } + + var logs []types.TrafficLogDetails + for _, v := range data { + logs = append(logs, types.TrafficLogDetails{ + Id: v.Id, + UserId: v.UserId, + ServerId: v.ServerId, + SubscribeId: v.SubscribeId, + Download: v.Download, + Upload: v.Upload, + Timestamp: v.Timestamp.UnixMilli(), + }) + } + + return &types.FilterTrafficLogDetailsResponse{ + List: logs, + Total: total, + }, nil +} diff --git a/internal/logic/admin/log/filterUserSubscribeTrafficLogLogic.go b/internal/logic/admin/log/filterUserSubscribeTrafficLogLogic.go new file mode 100644 index 0000000..f6c5a46 --- /dev/null +++ b/internal/logic/admin/log/filterUserSubscribeTrafficLogLogic.go @@ -0,0 +1,160 @@ +package log + +import ( + "context" + "time" + + "github.com/perfect-panel/server/internal/model/log" + "github.com/perfect-panel/server/internal/model/traffic" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" +) + +type FilterUserSubscribeTrafficLogLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// NewFilterUserSubscribeTrafficLogLogic Filter user subscribe traffic log +func NewFilterUserSubscribeTrafficLogLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FilterUserSubscribeTrafficLogLogic { + return &FilterUserSubscribeTrafficLogLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *FilterUserSubscribeTrafficLogLogic) FilterUserSubscribeTrafficLog(req *types.FilterSubscribeTrafficRequest) (resp *types.FilterSubscribeTrafficResponse, err error) { + if req.Size <= 0 { + req.Size = 10 + } + if req.Page <= 0 { + req.Page = 1 + } + + today := time.Now().Format("2006-01-02") + var list []types.UserSubscribeTrafficLog + var total int64 + + if req.Date == today || req.Date == "" { + now := time.Now() + start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local) + end := start.Add(24 * time.Hour).Add(-time.Nanosecond) + + var userTraffic []types.UserSubscribeTrafficLog + err = l.svcCtx.DB.WithContext(l.ctx). + Model(&traffic.TrafficLog{}). + Select("user_id, subscribe_id, SUM(download + upload) AS total, SUM(download) AS download, SUM(upload) AS upload"). + Where("timestamp BETWEEN ? AND ?", start, end). + Group("user_id, subscribe_id"). + Order("SUM(download + upload) DESC"). + Scan(&userTraffic).Error + if err != nil { + l.Errorw("[FilterUserSubscribeTrafficLog] Query Database Error", logger.Field("error", err.Error())) + return nil, err + } + + for _, v := range userTraffic { + list = append(list, types.UserSubscribeTrafficLog{ + UserId: v.UserId, + SubscribeId: v.SubscribeId, + Upload: v.Upload, + Download: v.Download, + Total: v.Total, + Date: today, + Details: true, + }) + } + todayTotal := len(list) + + startIdx := (req.Page - 1) * req.Size + endIdx := startIdx + req.Size + if startIdx < todayTotal { + if endIdx > todayTotal { + endIdx = todayTotal + } + pageData := list[startIdx:endIdx] + return &types.FilterSubscribeTrafficResponse{ + List: pageData, + Total: int64(todayTotal), + }, nil + } + + need := endIdx - todayTotal + historyPage := (need + req.Size - 1) / req.Size // 算出需要的历史页数 + historyData, historyTotal, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: historyPage, + Size: need, + Type: log.TypeSubscribeTraffic.Uint8(), + }) + + if err != nil { + l.Errorw("[FilterUserSubscribeTrafficLog] Query Database Error", logger.Field("error", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "[FilterUserSubscribeTrafficLog] Query Database Error") + } + + for _, datum := range historyData { + var item log.UserTraffic + err = item.Unmarshal([]byte(datum.Content)) + if err != nil { + l.Errorw("[FilterUserSubscribeTrafficLog] Unmarshal Content Error", logger.Field("error", err.Error())) + continue + } + list = append(list, types.UserSubscribeTrafficLog{ + UserId: item.UserId, + SubscribeId: item.SubscribeId, + Upload: item.Upload, + Download: item.Download, + Total: item.Total, + Date: datum.Date, + Details: false, + }) + } + // 返回最终分页数据 + if endIdx > len(list) { + endIdx = len(list) + } + pageData := list[startIdx:endIdx] + + return &types.FilterSubscribeTrafficResponse{ + List: pageData, + Total: int64(todayTotal) + historyTotal, + }, nil + } + var data []*log.SystemLog + data, total, err = l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: req.Page, + Size: req.Size, + Type: log.TypeSubscribeTraffic.Uint8(), + Data: req.Date, + }) + if err != nil { + l.Errorw("[FilterUserSubscribeTrafficLog] Query Database Error", logger.Field("error", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "[FilterUserSubscribeTrafficLog] Query Database Error") + } + for _, datum := range data { + var item log.UserTraffic + err = item.Unmarshal([]byte(datum.Content)) + if err != nil { + l.Errorw("[FilterUserSubscribeTrafficLog] Unmarshal Content Error", logger.Field("error", err.Error())) + continue + } + list = append(list, types.UserSubscribeTrafficLog{ + UserId: item.UserId, + SubscribeId: item.SubscribeId, + Upload: item.Upload, + Download: item.Download, + Total: item.Total, + Date: datum.Date, + Details: false, + }) + } + return &types.FilterSubscribeTrafficResponse{ + List: list, + Total: total, + }, nil +} diff --git a/internal/logic/admin/log/getLogSettingLogic.go b/internal/logic/admin/log/getLogSettingLogic.go new file mode 100644 index 0000000..568d7e0 --- /dev/null +++ b/internal/logic/admin/log/getLogSettingLogic.go @@ -0,0 +1,37 @@ +package log + +import ( + "context" + + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/tool" +) + +type GetLogSettingLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// Get log setting +func NewGetLogSettingLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetLogSettingLogic { + return &GetLogSettingLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *GetLogSettingLogic) GetLogSetting() (resp *types.LogSetting, err error) { + configs, err := l.svcCtx.SystemModel.GetLogConfig(l.ctx) + if err != nil { + l.Errorw("[GetLogSetting] Database query error", logger.Field("error", err.Error())) + return nil, err + } + resp = &types.LogSetting{} + // reflect to response + tool.SystemConfigSliceReflectToStruct(configs, resp) + return +} diff --git a/internal/logic/admin/log/getMessageLogListLogic.go b/internal/logic/admin/log/getMessageLogListLogic.go index b4ed00b..252028b 100644 --- a/internal/logic/admin/log/getMessageLogListLogic.go +++ b/internal/logic/admin/log/getMessageLogListLogic.go @@ -7,7 +7,6 @@ import ( "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" "github.com/perfect-panel/server/pkg/xerr" "github.com/pkg/errors" ) @@ -28,20 +27,39 @@ func NewGetMessageLogListLogic(ctx context.Context, svcCtx *svc.ServiceContext) } func (l *GetMessageLogListLogic) GetMessageLogList(req *types.GetMessageLogListRequest) (resp *types.GetMessageLogListResponse, err error) { - total, data, err := l.svcCtx.LogModel.FindMessageLogList(l.ctx, req.Page, req.Size, log.MessageLogFilterParams{ - Type: req.Type, - Platform: req.Platform, - To: req.To, - Subject: req.Subject, - Content: req.Content, - Status: req.Status, + + data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: req.Page, + Size: req.Size, + Type: req.Type, + Search: req.Search, }) + if err != nil { - l.Errorw("[GetMessageLogList] Database Error", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "[GetMessageLogList] Database Error: %s", err.Error()) + l.Errorf("[GetMessageLogList] failed to filter system log: %v", err.Error()) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "failed to filter system log: %v", err.Error()) } + var list []types.MessageLog - tool.DeepCopy(&list, data) + + for _, datum := range data { + var content log.Message + err = content.Unmarshal([]byte(datum.Content)) + if err != nil { + l.Errorf("[GetMessageLogList] failed to unmarshal content: %v", err.Error()) + continue + } + list = append(list, types.MessageLog{ + Id: datum.Id, + Type: datum.Type, + Platform: content.Platform, + To: content.To, + Subject: content.Subject, + Content: content.Content, + Status: content.Status, + CreatedAt: datum.CreatedAt.UnixMilli(), + }) + } return &types.GetMessageLogListResponse{ Total: total, diff --git a/internal/logic/admin/log/updateLogSettingLogic.go b/internal/logic/admin/log/updateLogSettingLogic.go new file mode 100644 index 0000000..39e5846 --- /dev/null +++ b/internal/logic/admin/log/updateLogSettingLogic.go @@ -0,0 +1,63 @@ +package log + +import ( + "context" + "reflect" + + "github.com/perfect-panel/server/internal/config" + "github.com/perfect-panel/server/internal/model/system" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/tool" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" + "gorm.io/gorm" +) + +type UpdateLogSettingLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// NewUpdateLogSettingLogic Update log setting +func NewUpdateLogSettingLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateLogSettingLogic { + return &UpdateLogSettingLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *UpdateLogSettingLogic) UpdateLogSetting(req *types.LogSetting) error { + v := reflect.ValueOf(*req) + // Get the reflection type of the structure + t := v.Type() + err := l.svcCtx.SystemModel.Transaction(l.ctx, func(db *gorm.DB) error { + var err error + for i := 0; i < v.NumField(); i++ { + // Get the field name + fieldName := t.Field(i).Name + // Get the field value to string + fieldValue := tool.ConvertValueToString(v.Field(i)) + // Update the server config + err = db.Model(&system.System{}).Where("`category` = 'log' and `key` = ?", fieldName).Update("value", fieldValue).Error + if err != nil { + break + } + } + return err + }) + if err != nil { + l.Errorw("[UpdateLogSetting] update log setting error", logger.Field("error", err.Error())) + return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), " update log setting error: %v", err) + } + + l.svcCtx.Config.Log = config.Log{ + AutoClear: *req.AutoClear, + ClearDays: req.ClearDays, + } + + return nil +} diff --git a/internal/logic/admin/marketing/createBatchSendEmailTaskLogic.go b/internal/logic/admin/marketing/createBatchSendEmailTaskLogic.go index 2542970..d2f181b 100644 --- a/internal/logic/admin/marketing/createBatchSendEmailTaskLogic.go +++ b/internal/logic/admin/marketing/createBatchSendEmailTaskLogic.go @@ -24,7 +24,7 @@ type CreateBatchSendEmailTaskLogic struct { svcCtx *svc.ServiceContext } -// Create a batch send email task +// NewCreateBatchSendEmailTaskLogic Create a batch send email task func NewCreateBatchSendEmailTaskLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateBatchSendEmailTaskLogic { return &CreateBatchSendEmailTaskLogic{ Logger: logger.WithContext(ctx), @@ -45,34 +45,37 @@ func (l *CreateBatchSendEmailTaskLogic) CreateBatchSendEmailTask(req *types.Crea Where("auth_type = ?", "email") if req.RegisterStartTime != 0 { - query = query.Where("user.created_at >= ?", req.RegisterStartTime) + query = query.Where("user.created_at >= ?", time.UnixMilli(req.RegisterStartTime)) } if req.RegisterEndTime != 0 { - query = query.Where("user.created_at <= ?", req.RegisterEndTime) + query = query.Where("user.created_at <= ?", time.UnixMilli(req.RegisterEndTime)) } return query } var query *gorm.DB - switch req.Scope { - case "all": + scope := task.ParseScopeType(req.Scope) + + switch scope { + case task.ScopeAll: query = baseQuery() - case "active": + case task.ScopeActive: query = baseQuery(). Joins("JOIN user_subscribe ON user.id = user_subscribe.user_id"). Where("user_subscribe.status IN ?", []int64{1, 2}) - case "expired": + case task.ScopeExpired: query = baseQuery(). Joins("JOIN user_subscribe ON user.id = user_subscribe.user_id"). Where("user_subscribe.status = ?", 3) - case "none": + case task.ScopeNone: query = baseQuery(). Joins("LEFT JOIN user_subscribe ON user.id = user_subscribe.user_id"). Where("user_subscribe.user_id IS NULL") + default: } if query != nil { @@ -85,7 +88,7 @@ func (l *CreateBatchSendEmailTaskLogic) CreateBatchSendEmailTask(req *types.Crea } // 邮箱列表为空,返回错误 - if len(emails) == 0 && req.Scope != "skip" { + if len(emails) == 0 && scope != task.ScopeSkip { l.Errorf("[CreateBatchSendEmailTask] No email addresses found for the specified scope") return xerr.NewErrMsg("No email addresses found for the specified scope") } @@ -96,41 +99,59 @@ func (l *CreateBatchSendEmailTaskLogic) CreateBatchSendEmailTask(req *types.Crea var additionalEmails []string // 追加额外的邮箱地址(不覆盖) if req.Additional != "" { - additionalEmails = strings.Split(req.Additional, "\n") + additionalEmails = tool.RemoveDuplicateElements(strings.Split(req.Additional, "\n")...) } - if len(additionalEmails) == 0 && req.Scope == "skip" { + if len(additionalEmails) == 0 && scope == task.ScopeSkip { l.Errorf("[CreateBatchSendEmailTask] No additional email addresses provided for skip scope") return xerr.NewErrMsg("No additional email addresses provided for skip scope") } - var scheduledAt time.Time - if req.Scheduled == 0 { - scheduledAt = time.Now() - } else { + scheduledAt := time.Now().Add(10 * time.Second) // 默认延迟10秒执行,防止任务创建和执行时间过于接近 + if req.Scheduled != 0 { scheduledAt = time.Unix(req.Scheduled, 0) if scheduledAt.Before(time.Now()) { scheduledAt = time.Now() } } - taskInfo := &task.EmailTask{ - Subject: req.Subject, - Content: req.Content, - Recipients: strings.Join(emails, "\n"), - Scope: req.Scope, - RegisterStartTime: time.Unix(req.RegisterStartTime, 0), - RegisterEndTime: time.Unix(req.RegisterEndTime, 0), - Additional: req.Additional, - Scheduled: scheduledAt, + scopeInfo := task.EmailScope{ + Type: scope.Int8(), + RegisterStartTime: req.RegisterStartTime, + RegisterEndTime: req.RegisterEndTime, + Recipients: emails, + Additional: additionalEmails, + Scheduled: req.Scheduled, Interval: req.Interval, Limit: req.Limit, - Status: 0, - Errors: "", - Total: uint64(len(emails) + len(additionalEmails)), - Current: 0, + } + scopeBytes, _ := scopeInfo.Marshal() + + taskContent := task.EmailContent{ + Subject: req.Subject, + Content: req.Content, } - if err = l.svcCtx.DB.Model(&task.EmailTask{}).Create(taskInfo).Error; err != nil { + contentBytes, _ := taskContent.Marshal() + + var total uint64 + if additionalEmails != nil { + list := append(emails, additionalEmails...) + total = uint64(len(tool.RemoveDuplicateElements(list...))) + } else { + total = uint64(len(emails)) + } + + taskInfo := &task.Task{ + Type: task.TypeEmail, + Scope: string(scopeBytes), + Content: string(contentBytes), + Status: 0, + Errors: "", + Total: total, + Current: 0, + } + + if err = l.svcCtx.DB.Model(&task.Task{}).Create(taskInfo).Error; err != nil { l.Errorf("[CreateBatchSendEmailTask] Failed to create email task: %v", err.Error()) return xerr.NewErrCode(xerr.DatabaseInsertError) } @@ -138,12 +159,12 @@ func (l *CreateBatchSendEmailTaskLogic) CreateBatchSendEmailTask(req *types.Crea l.Infof("[CreateBatchSendEmailTask] Successfully created email task with ID: %d", taskInfo.Id) t := asynq.NewTask(types2.ScheduledBatchSendEmail, []byte(strconv.FormatInt(taskInfo.Id, 10))) - info, err := l.svcCtx.Queue.EnqueueContext(l.ctx, t, asynq.ProcessAt(taskInfo.Scheduled)) + info, err := l.svcCtx.Queue.EnqueueContext(l.ctx, t, asynq.ProcessAt(scheduledAt)) if err != nil { l.Errorf("[CreateBatchSendEmailTask] Failed to enqueue email task: %v", err.Error()) return xerr.NewErrCode(xerr.QueueEnqueueError) } - l.Infof("[CreateBatchSendEmailTask] Successfully enqueued email task with ID: %s, scheduled at: %s", info.ID, taskInfo.Scheduled) + l.Infof("[CreateBatchSendEmailTask] Successfully enqueued email task with ID: %s, scheduled at: %s", info.ID, scheduledAt.Format(time.DateTime)) return nil } diff --git a/internal/logic/admin/marketing/createQuotaTaskLogic.go b/internal/logic/admin/marketing/createQuotaTaskLogic.go new file mode 100644 index 0000000..606435f --- /dev/null +++ b/internal/logic/admin/marketing/createQuotaTaskLogic.go @@ -0,0 +1,104 @@ +package marketing + +import ( + "context" + "strconv" + "time" + + "github.com/hibiken/asynq" + "github.com/perfect-panel/server/internal/model/task" + "github.com/perfect-panel/server/internal/model/user" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" + queueType "github.com/perfect-panel/server/queue/types" + "github.com/pkg/errors" +) + +type CreateQuotaTaskLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// NewCreateQuotaTaskLogic Create a quota task +func NewCreateQuotaTaskLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateQuotaTaskLogic { + return &CreateQuotaTaskLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *CreateQuotaTaskLogic) CreateQuotaTask(req *types.CreateQuotaTaskRequest) error { + var subs []*user.Subscribe + query := l.svcCtx.DB.WithContext(l.ctx).Model(&user.Subscribe{}) + if len(req.Subscribers) > 0 { + query = query.Where("`subscribe_id` IN ?", req.Subscribers) + } + + if req.IsActive != nil && *req.IsActive { + query = query.Where("`status` IN ?", []int64{0, 1, 2}) // 0: Pending 1: Active 2: Finished + } + if req.StartTime != 0 { + start := time.UnixMilli(req.StartTime) + query = query.Where("`start_time` <= ?", start) + } + if req.EndTime != 0 { + end := time.UnixMilli(req.EndTime) + query = query.Where("`expire_time` >= ?", end) + } + + if err := query.Find(&subs).Error; err != nil { + l.Errorf("[CreateQuotaTask] find subscribers error: %v", err.Error()) + return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find subscribers error") + } + if len(subs) == 0 { + return errors.Wrapf(xerr.NewErrMsg("No subscribers found"), "no subscribers found") + } + var subIds []int64 + for _, sub := range subs { + subIds = append(subIds, sub.Id) + } + + scopeInfo := task.QuotaScope{ + Subscribers: req.Subscribers, + IsActive: req.IsActive, + StartTime: req.StartTime, + EndTime: req.EndTime, + Objects: subIds, + } + scopeBytes, _ := scopeInfo.Marshal() + contentInfo := task.QuotaContent{ + ResetTraffic: req.ResetTraffic, + Days: req.Days, + GiftType: req.GiftType, + GiftValue: req.GiftValue, + } + contentBytes, _ := contentInfo.Marshal() + // create task + newTask := &task.Task{ + Type: task.TypeQuota, + Status: 0, + Scope: string(scopeBytes), + Content: string(contentBytes), + Total: uint64(len(subIds)), + Current: 0, + Errors: "", + } + + if err := l.svcCtx.DB.WithContext(l.ctx).Model(&task.Task{}).Create(newTask).Error; err != nil { + l.Errorf("[CreateQuotaTask] create task error: %v", err.Error()) + return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "create task error") + } + + // enqueue task + queueTask := asynq.NewTask(queueType.ForthwithQuotaTask, []byte(strconv.FormatInt(newTask.Id, 10))) + if _, err := l.svcCtx.Queue.EnqueueContext(l.ctx, queueTask); err != nil { + l.Errorf("[CreateQuotaTask] enqueue task error: %v", err.Error()) + return errors.Wrapf(xerr.NewErrCode(xerr.QueueEnqueueError), "enqueue task error") + } + logger.Infof("[CreateQuotaTask] Successfully created task with ID: %d", newTask.Id) + return nil +} diff --git a/internal/logic/admin/marketing/getBatchSendEmailTaskListLogic.go b/internal/logic/admin/marketing/getBatchSendEmailTaskListLogic.go index ec4f1bf..e3a3c7b 100644 --- a/internal/logic/admin/marketing/getBatchSendEmailTaskListLogic.go +++ b/internal/logic/admin/marketing/getBatchSendEmailTaskListLogic.go @@ -2,12 +2,12 @@ package marketing import ( "context" + "strings" "github.com/perfect-panel/server/internal/model/task" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" "github.com/perfect-panel/server/pkg/xerr" ) @@ -28,12 +28,12 @@ func NewGetBatchSendEmailTaskListLogic(ctx context.Context, svcCtx *svc.ServiceC func (l *GetBatchSendEmailTaskListLogic) GetBatchSendEmailTaskList(req *types.GetBatchSendEmailTaskListRequest) (resp *types.GetBatchSendEmailTaskListResponse, err error) { - var tasks []*task.EmailTask - tx := l.svcCtx.DB.Model(&task.EmailTask{}) + var tasks []*task.Task + tx := l.svcCtx.DB.Model(&task.Task{}).Where("`type` = ?", task.TypeEmail) if req.Status != nil { tx = tx.Where("status = ?", *req.Status) } - if req.Scope != "" { + if req.Scope != nil { tx = tx.Where("scope = ?", req.Scope) } if req.Page == 0 { @@ -49,7 +49,40 @@ func (l *GetBatchSendEmailTaskListLogic) GetBatchSendEmailTaskList(req *types.Ge } list := make([]types.BatchSendEmailTask, 0) - tool.DeepCopy(&list, tasks) + + for _, t := range tasks { + var scopeInfo task.EmailScope + if err = scopeInfo.Unmarshal([]byte(t.Scope)); err != nil { + l.Errorf("[GetBatchSendEmailTaskList] failed to unmarshal email task scope: %v", err.Error()) + continue + } + var contentInfo task.EmailContent + if err = contentInfo.Unmarshal([]byte(t.Content)); err != nil { + l.Errorf("[GetBatchSendEmailTaskList] failed to unmarshal email task content: %v", err.Error()) + continue + } + + list = append(list, types.BatchSendEmailTask{ + Id: t.Id, + Subject: contentInfo.Subject, + Content: contentInfo.Content, + Recipients: strings.Join(scopeInfo.Recipients, "\n"), + Scope: scopeInfo.Type, + RegisterStartTime: scopeInfo.RegisterStartTime, + RegisterEndTime: scopeInfo.RegisterEndTime, + Additional: strings.Join(scopeInfo.Additional, "\n"), + Scheduled: scopeInfo.Scheduled, + Interval: scopeInfo.Interval, + Limit: scopeInfo.Limit, + Status: uint8(t.Status), + Errors: t.Errors, + Total: t.Total, + Current: t.Current, + CreatedAt: t.CreatedAt.UnixMilli(), + UpdatedAt: t.UpdatedAt.UnixMilli(), + }) + } + return &types.GetBatchSendEmailTaskListResponse{ List: list, }, nil diff --git a/internal/logic/admin/marketing/getBatchSendEmailTaskStatusLogic.go b/internal/logic/admin/marketing/getBatchSendEmailTaskStatusLogic.go index eec1380..e21a7c5 100644 --- a/internal/logic/admin/marketing/getBatchSendEmailTaskStatusLogic.go +++ b/internal/logic/admin/marketing/getBatchSendEmailTaskStatusLogic.go @@ -28,15 +28,15 @@ func NewGetBatchSendEmailTaskStatusLogic(ctx context.Context, svcCtx *svc.Servic func (l *GetBatchSendEmailTaskStatusLogic) GetBatchSendEmailTaskStatus(req *types.GetBatchSendEmailTaskStatusRequest) (resp *types.GetBatchSendEmailTaskStatusResponse, err error) { tx := l.svcCtx.DB - var taskInfo *task.EmailTask - err = tx.Model(&task.EmailTask{}).Where("id = ?", req.Id).First(&taskInfo).Error + var taskInfo *task.Task + err = tx.Model(&task.Task{}).Where("id = ?", req.Id).First(&taskInfo).Error if err != nil { l.Errorf("failed to get email task status, error: %v", err) return nil, xerr.NewErrCode(xerr.DatabaseQueryError) } return &types.GetBatchSendEmailTaskStatusResponse{ - Status: taskInfo.Status, + Status: uint8(taskInfo.Status), Total: int64(taskInfo.Total), Current: int64(taskInfo.Current), Errors: taskInfo.Errors, diff --git a/internal/logic/admin/marketing/getPreSendEmailCountLogic.go b/internal/logic/admin/marketing/getPreSendEmailCountLogic.go index 32d73dc..9fbdbe4 100644 --- a/internal/logic/admin/marketing/getPreSendEmailCountLogic.go +++ b/internal/logic/admin/marketing/getPreSendEmailCountLogic.go @@ -2,7 +2,9 @@ package marketing import ( "context" + "time" + "github.com/perfect-panel/server/internal/model/task" "github.com/perfect-panel/server/internal/model/user" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" @@ -37,36 +39,41 @@ func (l *GetPreSendEmailCountLogic) GetPreSendEmailCount(req *types.GetPreSendEm Where("auth_type = ?", "email") if req.RegisterStartTime != 0 { - query = query.Where("user.created_at >= ?", req.RegisterStartTime) + + registerStartTime := time.UnixMilli(req.RegisterStartTime) + + query = query.Where("user.created_at >= ?", registerStartTime) } if req.RegisterEndTime != 0 { - query = query.Where("user.created_at <= ?", req.RegisterEndTime) + registerEndTime := time.UnixMilli(req.RegisterEndTime) + query = query.Where("user.created_at <= ?", registerEndTime) } return query } var query *gorm.DB - switch req.Scope { - case "all": + scope := task.ParseScopeType(req.Scope) + + switch scope { + case task.ScopeAll: query = baseQuery() - case "active": + case task.ScopeActive: query = baseQuery(). Joins("JOIN user_subscribe ON user.id = user_subscribe.user_id"). Where("user_subscribe.status IN ?", []int64{1, 2}) - case "expired": + case task.ScopeExpired: query = baseQuery(). Joins("JOIN user_subscribe ON user.id = user_subscribe.user_id"). Where("user_subscribe.status = ?", 3) - case "none": + case task.ScopeNone: query = baseQuery(). Joins("LEFT JOIN user_subscribe ON user.id = user_subscribe.user_id"). Where("user_subscribe.user_id IS NULL") - case "skip": + case task.ScopeSkip: // Skip scope does not require a count query = nil - default: l.Errorf("[CreateBatchSendEmailTask] Invalid scope: %v", req.Scope) return nil, xerr.NewErrMsg("Invalid email scope") diff --git a/internal/logic/admin/marketing/queryQuotaTaskListLogic.go b/internal/logic/admin/marketing/queryQuotaTaskListLogic.go new file mode 100644 index 0000000..50cfd9f --- /dev/null +++ b/internal/logic/admin/marketing/queryQuotaTaskListLogic.go @@ -0,0 +1,83 @@ +package marketing + +import ( + "context" + + "github.com/perfect-panel/server/internal/model/task" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" +) + +type QueryQuotaTaskListLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// NewQueryQuotaTaskListLogic Query quota task list +func NewQueryQuotaTaskListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryQuotaTaskListLogic { + return &QueryQuotaTaskListLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *QueryQuotaTaskListLogic) QueryQuotaTaskList(req *types.QueryQuotaTaskListRequest) (resp *types.QueryQuotaTaskListResponse, err error) { + var data []*task.Task + var count int64 + query := l.svcCtx.DB.Model(&task.Task{}).Where("`type` = ?", task.TypeQuota) + if req.Page == 0 { + req.Page = 1 + } + if req.Size == 0 { + req.Size = 20 + } + + if req.Status != nil { + query = query.Where("`status` = ?", *req.Status) + } + err = query.Count(&count).Offset((req.Page - 1) * req.Size).Limit(req.Size).Order("created_at DESC").Find(&data).Error + if err != nil { + l.Errorf("[QueryQuotaTaskList] failed to get quota tasks: %v", err) + return nil, err + } + + var list []types.QuotaTask + for _, item := range data { + var scopeInfo task.QuotaScope + if err = scopeInfo.Unmarshal([]byte(item.Scope)); err != nil { + l.Errorf("[QueryQuotaTaskList] failed to unmarshal quota task scope: %v", err.Error()) + continue + } + var contentInfo task.QuotaContent + if err = contentInfo.Unmarshal([]byte(item.Content)); err != nil { + l.Errorf("[QueryQuotaTaskList] failed to unmarshal quota task content: %v", err.Error()) + continue + } + list = append(list, types.QuotaTask{ + Id: item.Id, + Subscribers: scopeInfo.Subscribers, + IsActive: scopeInfo.IsActive, + StartTime: scopeInfo.StartTime, + EndTime: scopeInfo.EndTime, + ResetTraffic: contentInfo.ResetTraffic, + Days: contentInfo.Days, + GiftType: contentInfo.GiftType, + GiftValue: contentInfo.GiftValue, + Objects: scopeInfo.Objects, + Status: uint8(item.Status), + Total: int64(item.Total), + Current: int64(item.Current), + Errors: item.Errors, + CreatedAt: item.CreatedAt.UnixMilli(), + UpdatedAt: item.UpdatedAt.UnixMilli(), + }) + } + + return &types.QueryQuotaTaskListResponse{ + Total: count, + List: list, + }, nil +} diff --git a/internal/logic/admin/marketing/queryQuotaTaskPreCountLogic.go b/internal/logic/admin/marketing/queryQuotaTaskPreCountLogic.go new file mode 100644 index 0000000..21b0cb4 --- /dev/null +++ b/internal/logic/admin/marketing/queryQuotaTaskPreCountLogic.go @@ -0,0 +1,55 @@ +package marketing + +import ( + "context" + "time" + + "github.com/perfect-panel/server/internal/model/user" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" +) + +type QueryQuotaTaskPreCountLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// NewQueryQuotaTaskPreCountLogic Query quota task pre-count +func NewQueryQuotaTaskPreCountLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryQuotaTaskPreCountLogic { + return &QueryQuotaTaskPreCountLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *QueryQuotaTaskPreCountLogic) QueryQuotaTaskPreCount(req *types.QueryQuotaTaskPreCountRequest) (resp *types.QueryQuotaTaskPreCountResponse, err error) { + tx := l.svcCtx.DB.WithContext(l.ctx).Model(&user.Subscribe{}) + var count int64 + + if len(req.Subscribers) > 0 { + tx = tx.Where("`subscribe_id` IN ?", req.Subscribers) + } + + if req.IsActive != nil && *req.IsActive { + tx = tx.Where("`status` IN ?", []int64{0, 1, 2}) // 0: Pending 1: Active 2: Finished + } + if req.StartTime != 0 { + start := time.UnixMilli(req.StartTime) + tx = tx.Where("`start_time` <= ?", start) + } + if req.EndTime != 0 { + end := time.UnixMilli(req.EndTime) + tx = tx.Where("`expire_time` >= ?", end) + } + if err = tx.Count(&count).Error; err != nil { + l.Errorf("[QueryQuotaTaskPreCount] count error: %v", err.Error()) + return nil, err + } + + return &types.QueryQuotaTaskPreCountResponse{ + Count: count, + }, nil +} diff --git a/internal/logic/admin/marketing/queryQuotaTaskStatusLogic.go b/internal/logic/admin/marketing/queryQuotaTaskStatusLogic.go new file mode 100644 index 0000000..70599fe --- /dev/null +++ b/internal/logic/admin/marketing/queryQuotaTaskStatusLogic.go @@ -0,0 +1,42 @@ +package marketing + +import ( + "context" + + "github.com/perfect-panel/server/internal/model/task" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" +) + +type QueryQuotaTaskStatusLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// NewQueryQuotaTaskStatusLogic Query quota task status +func NewQueryQuotaTaskStatusLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryQuotaTaskStatusLogic { + return &QueryQuotaTaskStatusLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *QueryQuotaTaskStatusLogic) QueryQuotaTaskStatus(req *types.QueryQuotaTaskStatusRequest) (resp *types.QueryQuotaTaskStatusResponse, err error) { + var data *task.Task + err = l.svcCtx.DB.Model(&task.Task{}).Where("id = ? AND `type` = ?", req.Id, task.TypeQuota).First(&data).Error + if err != nil { + l.Errorf("[QueryQuotaTaskStatus] failed to get quota task: %v", err.Error()) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), " failed to get quota task: %v", err.Error()) + } + return &types.QueryQuotaTaskStatusResponse{ + Status: uint8(data.Status), + Current: int64(data.Current), + Total: int64(data.Total), + Errors: data.Errors, + }, nil +} diff --git a/internal/logic/admin/marketing/stopBatchSendEmailTaskLogic.go b/internal/logic/admin/marketing/stopBatchSendEmailTaskLogic.go index 3b1d47d..da3949f 100644 --- a/internal/logic/admin/marketing/stopBatchSendEmailTaskLogic.go +++ b/internal/logic/admin/marketing/stopBatchSendEmailTaskLogic.go @@ -32,7 +32,7 @@ func (l *StopBatchSendEmailTaskLogic) StopBatchSendEmailTask(req *types.StopBatc } else { logger.Error("[StopBatchSendEmailTaskLogic] email.Manager is nil, cannot stop task") } - err = l.svcCtx.DB.Model(&task.EmailTask{}).Where("id = ?", req.Id).Update("status", 2).Error + err = l.svcCtx.DB.Model(&task.Task{}).Where("id = ?", req.Id).Update("status", 2).Error if err != nil { l.Errorf("failed to stop email task, error: %v", err) diff --git a/internal/logic/admin/payment/createPaymentMethodLogic.go b/internal/logic/admin/payment/createPaymentMethodLogic.go index 014f595..23cd48d 100644 --- a/internal/logic/admin/payment/createPaymentMethodLogic.go +++ b/internal/logic/admin/payment/createPaymentMethodLogic.go @@ -55,10 +55,9 @@ func (l *CreatePaymentMethodLogic) CreatePaymentMethod(req *types.CreatePaymentM Token: random.KeyNew(8, 1), } err = l.svcCtx.PaymentModel.Transaction(l.ctx, func(tx *gorm.DB) error { - if req.Platform == "Stripe" { var cfg paymentModel.StripeConfig - if err := cfg.Unmarshal(paymentMethod.Config); err != nil { + if err = cfg.Unmarshal([]byte(paymentMethod.Config)); err != nil { l.Errorf("[CreatePaymentMethod] unmarshal stripe config error: %s", err.Error()) return errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "unmarshal stripe config error: %s", err.Error()) } @@ -79,7 +78,8 @@ func (l *CreatePaymentMethodLogic) CreatePaymentMethod(req *types.CreatePaymentM return errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "create stripe webhook endpoint error: %s", err.Error()) } cfg.WebhookSecret = endpoint.Secret - paymentMethod.Config = cfg.Marshal() + content, _ := cfg.Marshal() + paymentMethod.Config = string(content) } if err = tx.Model(&paymentModel.Payment{}).Create(paymentMethod).Error; err != nil { return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "insert payment method error: %s", err.Error()) @@ -101,27 +101,36 @@ func (l *CreatePaymentMethodLogic) CreatePaymentMethod(req *types.CreatePaymentM func parsePaymentPlatformConfig(ctx context.Context, platform payment.Platform, config interface{}) string { data, err := json.Marshal(config) if err != nil { - logger.WithContext(ctx).Errorw("parse payment platform config error", logger.Field("platform", platform), logger.Field("config", config), logger.Field("error", err.Error())) + logger.WithContext(ctx).Errorw("marshal config error", logger.Field("platform", platform), logger.Field("config", config), logger.Field("error", err.Error())) + return "" } + + // 通用处理函数 + handleConfig := func(name string, target interface { + Unmarshal([]byte) error + Marshal() ([]byte, error) + }) string { + if err = target.Unmarshal(data); err != nil { + logger.WithContext(ctx).Errorw("parse "+name+" config error", logger.Field("config", string(data)), logger.Field("error", err.Error())) + return "" + } + content, err := target.Marshal() + if err != nil { + logger.WithContext(ctx).Errorw("marshal "+name+" config error", logger.Field("error", err.Error())) + return "" + } + return string(content) + } + switch platform { case payment.Stripe: - stripe := &paymentModel.StripeConfig{} - if err := stripe.Unmarshal(string(data)); err != nil { - logger.WithContext(ctx).Errorw("parse stripe config error", logger.Field("config", string(data)), logger.Field("error", err.Error())) - } - return stripe.Marshal() + return handleConfig("Stripe", &paymentModel.StripeConfig{}) case payment.AlipayF2F: - alipay := &paymentModel.AlipayF2FConfig{} - if err := alipay.Unmarshal(string(data)); err != nil { - logger.WithContext(ctx).Errorw("parse alipay config error", logger.Field("config", string(data)), logger.Field("error", err.Error())) - } - return alipay.Marshal() + return handleConfig("Alipay", &paymentModel.AlipayF2FConfig{}) case payment.EPay: - epay := &paymentModel.EPayConfig{} - if err := epay.Unmarshal(string(data)); err != nil { - logger.WithContext(ctx).Errorw("parse epay config error", logger.Field("config", string(data)), logger.Field("error", err.Error())) - } - return epay.Marshal() + return handleConfig("Epay", &paymentModel.EPayConfig{}) + case payment.CryptoSaaS: + return handleConfig("CryptoSaaS", &paymentModel.CryptoSaaSConfig{}) default: return "" } diff --git a/internal/logic/admin/payment/updatePaymentMethodLogic.go b/internal/logic/admin/payment/updatePaymentMethodLogic.go index 87b4fd7..7c2dda2 100644 --- a/internal/logic/admin/payment/updatePaymentMethodLogic.go +++ b/internal/logic/admin/payment/updatePaymentMethodLogic.go @@ -19,7 +19,7 @@ type UpdatePaymentMethodLogic struct { svcCtx *svc.ServiceContext } -// Update Payment Method +// NewUpdatePaymentMethodLogic Update Payment Method func NewUpdatePaymentMethodLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdatePaymentMethodLogic { return &UpdatePaymentMethodLogic{ Logger: logger.WithContext(ctx), diff --git a/internal/logic/admin/server/batchDeleteNodeGroupLogic.go b/internal/logic/admin/server/batchDeleteNodeGroupLogic.go deleted file mode 100644 index 5353475..0000000 --- a/internal/logic/admin/server/batchDeleteNodeGroupLogic.go +++ /dev/null @@ -1,44 +0,0 @@ -package server - -import ( - "context" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type BatchDeleteNodeGroupLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -func NewBatchDeleteNodeGroupLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BatchDeleteNodeGroupLogic { - return &BatchDeleteNodeGroupLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *BatchDeleteNodeGroupLogic) BatchDeleteNodeGroup(req *types.BatchDeleteNodeGroupRequest) error { - // Check if the group is empty - count, err := l.svcCtx.ServerModel.QueryServerCountByServerGroups(l.ctx, req.Ids) - if err != nil { - l.Errorw("[BatchDeleteNodeGroup] Query Database Error: ", logger.Field("error", err.Error())) - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query server error: %v", err) - } - if count > 0 { - return errors.Wrapf(xerr.NewErrCode(xerr.NodeGroupNotEmpty), "group is not empty") - } - // Delete the group - err = l.svcCtx.ServerModel.BatchDeleteNodeGroup(l.ctx, req.Ids) - if err != nil { - l.Errorw("[BatchDeleteNodeGroup] Delete Database Error: ", logger.Field("error", err.Error())) - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseDeletedError), err.Error()) - } - return nil -} diff --git a/internal/logic/admin/server/batchDeleteNodeLogic.go b/internal/logic/admin/server/batchDeleteNodeLogic.go deleted file mode 100644 index 6b03806..0000000 --- a/internal/logic/admin/server/batchDeleteNodeLogic.go +++ /dev/null @@ -1,43 +0,0 @@ -package server - -import ( - "context" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - "gorm.io/gorm" -) - -type BatchDeleteNodeLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -func NewBatchDeleteNodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BatchDeleteNodeLogic { - return &BatchDeleteNodeLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *BatchDeleteNodeLogic) BatchDeleteNode(req *types.BatchDeleteNodeRequest) error { - err := l.svcCtx.DB.Transaction(func(db *gorm.DB) error { - for _, id := range req.Ids { - err := l.svcCtx.ServerModel.Delete(l.ctx, id) - if err != nil { - return err - } - } - return nil - }) - if err != nil { - l.Errorw("[BatchDeleteNode] Delete Database Error: ", logger.Field("error", err.Error())) - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseDeletedError), err.Error()) - } - return nil -} diff --git a/internal/logic/admin/server/constant.go b/internal/logic/admin/server/constant.go new file mode 100644 index 0000000..ae06fea --- /dev/null +++ b/internal/logic/admin/server/constant.go @@ -0,0 +1,11 @@ +package server + +const ( + ShadowSocks = "shadowsocks" + Vmess = "vmess" + Vless = "vless" + Trojan = "trojan" + AnyTLS = "anytls" + Tuic = "tuic" + Hysteria2 = "hysteria2" +) diff --git a/internal/logic/admin/server/createNodeGroupLogic.go b/internal/logic/admin/server/createNodeGroupLogic.go deleted file mode 100644 index b194a24..0000000 --- a/internal/logic/admin/server/createNodeGroupLogic.go +++ /dev/null @@ -1,40 +0,0 @@ -package server - -import ( - "context" - - "github.com/perfect-panel/server/internal/model/server" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/xerr" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - - "github.com/pkg/errors" -) - -type CreateNodeGroupLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -func NewCreateNodeGroupLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateNodeGroupLogic { - return &CreateNodeGroupLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *CreateNodeGroupLogic) CreateNodeGroup(req *types.CreateNodeGroupRequest) error { - groupInfo := &server.Group{ - Name: req.Name, - Description: req.Description, - } - err := l.svcCtx.ServerModel.InsertGroup(l.ctx, groupInfo) - if err != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), err.Error()) - } - return nil -} diff --git a/internal/logic/admin/server/createNodeLogic.go b/internal/logic/admin/server/createNodeLogic.go index c25f9e1..f635f85 100644 --- a/internal/logic/admin/server/createNodeLogic.go +++ b/internal/logic/admin/server/createNodeLogic.go @@ -2,18 +2,13 @@ package server import ( "context" - "encoding/json" - "strings" - "time" - "github.com/hibiken/asynq" - "github.com/perfect-panel/server/internal/model/server" + "github.com/perfect-panel/server/internal/model/node" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" "github.com/perfect-panel/server/pkg/tool" "github.com/perfect-panel/server/pkg/xerr" - queue "github.com/perfect-panel/server/queue/types" "github.com/pkg/errors" ) @@ -23,6 +18,7 @@ type CreateNodeLogic struct { svcCtx *svc.ServiceContext } +// NewCreateNodeLogic Create Node func NewCreateNodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateNodeLogic { return &CreateNodeLogic{ Logger: logger.WithContext(ctx), @@ -32,97 +28,18 @@ func NewCreateNodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Create } func (l *CreateNodeLogic) CreateNode(req *types.CreateNodeRequest) error { - config, err := json.Marshal(req.Config) - if err != nil { - return err + data := node.Node{ + Name: req.Name, + Tags: tool.StringSliceToString(req.Tags), + Port: req.Port, + Address: req.Address, + ServerId: req.ServerId, + Protocol: req.Protocol, } - var serverInfo server.Server - tool.DeepCopy(&serverInfo, req) - serverInfo.Config = string(config) - nodeRelay, err := json.Marshal(req.RelayNode) - if err != nil { - l.Errorw("[UpdateNode] Marshal RelayNode Error: ", logger.Field("error", err.Error())) - return err - } - if len(req.Tags) > 0 { - serverInfo.Tags = strings.Join(req.Tags, ",") - } - - serverInfo.LastReportedAt = time.UnixMicro(1218124800) - - serverInfo.City = req.City - serverInfo.Country = req.Country - - serverInfo.RelayNode = string(nodeRelay) - if req.Protocol == "vless" { - var cfg types.Vless - if err = json.Unmarshal(config, &cfg); err != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "json.Unmarshal error: %v", err.Error()) - } - if cfg.Security == "reality" && cfg.SecurityConfig.RealityPublicKey == "" { - public, private, err := tool.Curve25519Genkey(false, "") - if err != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "generate curve25519 key error") - } - cfg.SecurityConfig.RealityPublicKey = public - cfg.SecurityConfig.RealityPrivateKey = private - cfg.SecurityConfig.RealityShortId = tool.GenerateShortID(private) - } - if cfg.SecurityConfig.RealityServerAddr == "" { - cfg.SecurityConfig.RealityServerAddr = cfg.SecurityConfig.SNI - } - if cfg.SecurityConfig.RealityServerPort == 0 { - cfg.SecurityConfig.RealityServerPort = 443 - } - config, _ = json.Marshal(cfg) - serverInfo.Config = string(config) - } else if req.Protocol == "shadowsocks" { - var cfg types.Shadowsocks - if err = json.Unmarshal(config, &cfg); err != nil { - l.Errorf("[CreateNode] Unmarshal Shadowsocks Config Error: %v", err.Error()) - return errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "json.Unmarshal error: %v", err.Error()) - } - if strings.Contains(cfg.Method, "2022") { - var length int - switch cfg.Method { - case "2022-blake3-aes-128-gcm": - length = 16 - default: - length = 32 - } - if len(cfg.ServerKey) != length { - cfg.ServerKey = tool.GenerateCipher(cfg.ServerKey, length) - } - } - config, _ = json.Marshal(cfg) - serverInfo.Config = string(config) - } - - err = l.svcCtx.ServerModel.Insert(l.ctx, &serverInfo) + err := l.svcCtx.NodeModel.InsertNode(l.ctx, &data) if err != nil { l.Errorw("[CreateNode] Insert Database Error: ", logger.Field("error", err.Error())) - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "create server error: %v", err) - } - - if req.City == "" || req.Country == "" { - // Marshal the task payload - payload, err := json.Marshal(queue.GetNodeCountry{ - Protocol: serverInfo.Protocol, - ServerAddr: serverInfo.ServerAddr, - }) - if err != nil { - l.Errorw("[GetNodeCountry]: Marshal Error", logger.Field("error", err.Error())) - return errors.Wrap(xerr.NewErrCode(xerr.ERROR), "Failed to marshal task payload") - } - // Create a queue task - task := asynq.NewTask(queue.ForthwithGetCountry, payload) - // Enqueue the task - taskInfo, err := l.svcCtx.Queue.Enqueue(task) - if err != nil { - l.Errorw("[GetNodeCountry]: Enqueue Error", logger.Field("error", err.Error()), logger.Field("payload", string(payload))) - return errors.Wrap(xerr.NewErrCode(xerr.ERROR), "Failed to enqueue task") - } - l.Infow("[GetNodeCountry]: Enqueue Success", logger.Field("taskID", taskInfo.ID), logger.Field("payload", string(payload))) + return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "[CreateNode] Insert Database Error") } return nil diff --git a/internal/logic/admin/server/createRuleGroupLogic.go b/internal/logic/admin/server/createRuleGroupLogic.go deleted file mode 100644 index 619fbe7..0000000 --- a/internal/logic/admin/server/createRuleGroupLogic.go +++ /dev/null @@ -1,78 +0,0 @@ -package server - -import ( - "context" - "strings" - - "github.com/perfect-panel/server/pkg/rules" - - "github.com/perfect-panel/server/internal/model/server" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type CreateRuleGroupLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Create rule group -func NewCreateRuleGroupLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateRuleGroupLogic { - return &CreateRuleGroupLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} -func parseAndValidateRules(ruleText, ruleName string) ([]string, error) { - var rs []string - ruleArr := strings.Split(ruleText, "\n") - if len(ruleArr) == 0 { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "rules is empty") - } - - for _, s := range ruleArr { - r := rules.NewRule(s, ruleName) - if r == nil { - continue - } - if err := r.Validate(); err != nil { - continue - } - rs = append(rs, r.String()) - } - return rs, nil -} -func (l *CreateRuleGroupLogic) CreateRuleGroup(req *types.CreateRuleGroupRequest) error { - rs, err := parseAndValidateRules(req.Rules, req.Name) - if err != nil { - return err - } - info := &server.RuleGroup{ - Name: req.Name, - Icon: req.Icon, - Type: req.Type, - Tags: tool.StringSliceToString(req.Tags), - Rules: strings.Join(rs, "\n"), - Default: req.Default, - Enable: req.Enable, - } - err = l.svcCtx.ServerModel.InsertRuleGroup(l.ctx, info) - if err != nil { - l.Errorw("[CreateRuleGroup] Insert Database Error: ", logger.Field("error", err.Error())) - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "create server rule group error: %v", err) - } - if req.Default { - if err = l.svcCtx.ServerModel.SetDefaultRuleGroup(l.ctx, info.Id); err != nil { - l.Errorw("[CreateRuleGroup] Set Default Rule Group Error: ", logger.Field("error", err.Error())) - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "set default rule group error: %v", err) - } - } - - return nil -} diff --git a/internal/logic/admin/server/createServerLogic.go b/internal/logic/admin/server/createServerLogic.go new file mode 100644 index 0000000..cc2da85 --- /dev/null +++ b/internal/logic/admin/server/createServerLogic.go @@ -0,0 +1,111 @@ +package server + +import ( + "context" + "strings" + + "github.com/perfect-panel/server/internal/model/node" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/ip" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/tool" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" +) + +type CreateServerLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// NewCreateServerLogic Create Server +func NewCreateServerLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateServerLogic { + return &CreateServerLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *CreateServerLogic) CreateServer(req *types.CreateServerRequest) error { + data := node.Server{ + Name: req.Name, + Country: req.Country, + City: req.City, + Ratio: req.Ratio, + Address: req.Address, + Sort: req.Sort, + Protocols: "", + } + protocols := make([]node.Protocol, 0) + for _, item := range req.Protocols { + if item.Type == "" { + return errors.Wrapf(xerr.NewErrCodeMsg(xerr.InvalidParams, "protocols type is empty"), "protocols type is empty") + } + var protocol node.Protocol + tool.DeepCopy(&protocol, item) + + // VLESS Reality Key Generation + if protocol.Type == "vless" { + if protocol.Security == "reality" { + if protocol.RealityPublicKey == "" { + public, private, err := tool.Curve25519Genkey(false, "") + if err != nil { + l.Errorf("[CreateServer] Generate Reality Key Error: %v", err.Error()) + return errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "generate reality key error: %v", err) + } + protocol.RealityPublicKey = public + protocol.RealityPrivateKey = private + protocol.RealityShortId = tool.GenerateShortID(private) + } + if protocol.RealityServerAddr == "" { + protocol.RealityServerAddr = protocol.SNI + } + if protocol.RealityServerPort == 0 { + protocol.RealityServerPort = 443 + } + } + + } + // ShadowSocks 2022 Key Generation + if protocol.Type == "shadowsocks" { + if strings.Contains(protocol.Cipher, "2022") { + var length int + switch protocol.Cipher { + case "2022-blake3-aes-128-gcm": + length = 16 + default: + length = 32 + } + if len(protocol.ServerKey) != length { + protocol.ServerKey = tool.GenerateCipher(protocol.ServerKey, length) + } + } + } + protocols = append(protocols, protocol) + } + + err := data.MarshalProtocols(protocols) + if err != nil { + l.Errorf("[CreateServer] Marshal Protocols Error: %v", err.Error()) + return errors.Wrapf(xerr.NewErrCodeMsg(xerr.InvalidParams, "protocols marshal error"), "protocols marshal error: %v", err) + } + if data.City == "" && data.Country == "" { + // query server ip location + result, err := ip.GetRegionByIp(req.Address) + if err != nil { + l.Errorf("[CreateServer] GetRegionByIp Error: %v", err.Error()) + } else { + data.City = result.City + data.Country = result.Country + } + } + err = l.svcCtx.NodeModel.InsertServer(l.ctx, &data) + if err != nil { + l.Errorf("[CreateServer] Insert Server error: %v", err.Error()) + return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "insert server error: %v", err) + } + return nil +} diff --git a/internal/logic/admin/server/deleteNodeGroupLogic.go b/internal/logic/admin/server/deleteNodeGroupLogic.go deleted file mode 100644 index 04d420e..0000000 --- a/internal/logic/admin/server/deleteNodeGroupLogic.go +++ /dev/null @@ -1,44 +0,0 @@ -package server - -import ( - "context" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type DeleteNodeGroupLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -func NewDeleteNodeGroupLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteNodeGroupLogic { - return &DeleteNodeGroupLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *DeleteNodeGroupLogic) DeleteNodeGroup(req *types.DeleteNodeGroupRequest) error { - // Check if the group is empty - count, err := l.svcCtx.ServerModel.QueryServerCountByServerGroups(l.ctx, []int64{req.Id}) - if err != nil { - l.Errorw("[DeleteNodeGroup] Query Database Error: ", logger.Field("error", err.Error())) - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query server error: %v", err) - } - if count > 0 { - return errors.Wrapf(xerr.NewErrCode(xerr.NodeGroupNotEmpty), "group is not empty") - } - // Delete the group - err = l.svcCtx.ServerModel.DeleteGroup(l.ctx, req.Id) - if err != nil { - l.Errorw("[DeleteNodeGroup] Delete Database Error: ", logger.Field("error", err.Error())) - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseDeletedError), err.Error()) - } - return nil -} diff --git a/internal/logic/admin/server/deleteNodeLogic.go b/internal/logic/admin/server/deleteNodeLogic.go index cd4e4c6..a8839be 100644 --- a/internal/logic/admin/server/deleteNodeLogic.go +++ b/internal/logic/admin/server/deleteNodeLogic.go @@ -2,14 +2,12 @@ package server import ( "context" - "github.com/perfect-panel/server/pkg/tool" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" "github.com/perfect-panel/server/pkg/xerr" "github.com/pkg/errors" - "gorm.io/gorm" ) type DeleteNodeLogic struct { @@ -18,6 +16,7 @@ type DeleteNodeLogic struct { svcCtx *svc.ServiceContext } +// NewDeleteNodeLogic Delete Node func NewDeleteNodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteNodeLogic { return &DeleteNodeLogic{ Logger: logger.WithContext(ctx), @@ -27,33 +26,10 @@ func NewDeleteNodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Delete } func (l *DeleteNodeLogic) DeleteNode(req *types.DeleteNodeRequest) error { - err := l.svcCtx.DB.Transaction(func(tx *gorm.DB) error { - // Delete server - err := l.svcCtx.ServerModel.Delete(l.ctx, req.Id, tx) - if err != nil { - return err - } - // Delete server to subscribe - subs, err := l.svcCtx.SubscribeModel.QuerySubscribeIdsByServerIdAndServerGroupId(l.ctx, req.Id, 0) - if err != nil { - l.Logger.Errorf("[DeleteNode] QuerySubscribeIdsByServerIdAndServerGroupId error: %v", err.Error()) - return err - } - - for _, sub := range subs { - servers := tool.StringToInt64Slice(sub.Server) - newServers := tool.RemoveElementBySlice(servers, req.Id) - sub.Server = tool.Int64SliceToString(newServers) - if err = l.svcCtx.SubscribeModel.Update(l.ctx, sub, tx); err != nil { - l.Logger.Errorf("[DeleteNode] UpdateSubscribe error: %v", err.Error()) - return err - } - } - return nil - }) + err := l.svcCtx.NodeModel.DeleteNode(l.ctx, req.Id) if err != nil { l.Errorw("[DeleteNode] Delete Database Error: ", logger.Field("error", err.Error())) - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseDeletedError), "delete server error: %v", err) + return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseDeletedError), "[DeleteNode] Delete Database Error") } return nil } diff --git a/internal/logic/admin/server/deleteRuleGroupLogic.go b/internal/logic/admin/server/deleteServerLogic.go similarity index 50% rename from internal/logic/admin/server/deleteRuleGroupLogic.go rename to internal/logic/admin/server/deleteServerLogic.go index f0e1110..912a18c 100644 --- a/internal/logic/admin/server/deleteRuleGroupLogic.go +++ b/internal/logic/admin/server/deleteServerLogic.go @@ -10,26 +10,26 @@ import ( "github.com/pkg/errors" ) -type DeleteRuleGroupLogic struct { +type DeleteServerLogic struct { logger.Logger ctx context.Context svcCtx *svc.ServiceContext } -// Delete rule group -func NewDeleteRuleGroupLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteRuleGroupLogic { - return &DeleteRuleGroupLogic{ +// NewDeleteServerLogic Delete Server +func NewDeleteServerLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteServerLogic { + return &DeleteServerLogic{ Logger: logger.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, } } -func (l *DeleteRuleGroupLogic) DeleteRuleGroup(req *types.DeleteRuleGroupRequest) error { - err := l.svcCtx.ServerModel.DeleteRuleGroup(l.ctx, req.Id) +func (l *DeleteServerLogic) DeleteServer(req *types.DeleteServerRequest) error { + err := l.svcCtx.NodeModel.DeleteServer(l.ctx, req.Id) if err != nil { - l.Errorw("[DeleteRuleGroup] Delete Database Error: ", logger.Field("error", err.Error())) - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseDeletedError), "delete server rule group error: %v", err) + l.Errorw("[DeleteServer] Delete Server Error: ", logger.Field("error", err.Error())) + return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseDeletedError), "[DeleteServer] Delete Server Error") } return nil } diff --git a/internal/logic/admin/server/filterNodeListLogic.go b/internal/logic/admin/server/filterNodeListLogic.go new file mode 100644 index 0000000..2e41cec --- /dev/null +++ b/internal/logic/admin/server/filterNodeListLogic.go @@ -0,0 +1,64 @@ +package server + +import ( + "context" + "strings" + + "github.com/perfect-panel/server/internal/model/node" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/tool" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" +) + +type FilterNodeListLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// NewFilterNodeListLogic Filter Node List +func NewFilterNodeListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FilterNodeListLogic { + return &FilterNodeListLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *FilterNodeListLogic) FilterNodeList(req *types.FilterNodeListRequest) (resp *types.FilterNodeListResponse, err error) { + total, data, err := l.svcCtx.NodeModel.FilterNodeList(l.ctx, &node.FilterNodeParams{ + Page: req.Page, + Size: req.Size, + Search: req.Search, + }) + + if err != nil { + l.Errorw("[FilterNodeList] Query Database Error: ", logger.Field("error", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "[FilterNodeList] Query Database Error") + } + + list := make([]types.Node, 0) + for _, datum := range data { + list = append(list, types.Node{ + Id: datum.Id, + Name: datum.Name, + Tags: tool.RemoveDuplicateElements(strings.Split(datum.Tags, ",")...), + Port: datum.Port, + Address: datum.Address, + ServerId: datum.ServerId, + Protocol: datum.Protocol, + Enabled: datum.Enabled, + Sort: datum.Sort, + CreatedAt: datum.CreatedAt.UnixMilli(), + UpdatedAt: datum.UpdatedAt.UnixMilli(), + }) + } + + return &types.FilterNodeListResponse{ + List: list, + Total: total, + }, nil +} diff --git a/internal/logic/admin/server/filterServerListLogic.go b/internal/logic/admin/server/filterServerListLogic.go new file mode 100644 index 0000000..fb47ffa --- /dev/null +++ b/internal/logic/admin/server/filterServerListLogic.go @@ -0,0 +1,164 @@ +package server + +import ( + "context" + "time" + + "github.com/perfect-panel/server/internal/model/node" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/tool" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" + "github.com/redis/go-redis/v9" + "gorm.io/gorm" +) + +type FilterServerListLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// NewFilterServerListLogic Filter Server List +func NewFilterServerListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FilterServerListLogic { + return &FilterServerListLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *FilterServerListLogic) FilterServerList(req *types.FilterServerListRequest) (resp *types.FilterServerListResponse, err error) { + total, data, err := l.svcCtx.NodeModel.FilterServerList(l.ctx, &node.FilterParams{ + Page: req.Page, + Size: req.Size, + Search: req.Search, + }) + if err != nil { + l.Errorw("[FilterServerList] Query Database Error: ", logger.Field("error", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "[FilterServerList] Query Database Error") + } + + list := make([]types.Server, 0) + + for _, datum := range data { + var server types.Server + tool.DeepCopy(&server, datum) + + // handler protocols + var protocols []types.Protocol + dst, err := datum.UnmarshalProtocols() + if err != nil { + l.Errorf("[FilterServerList] UnmarshalProtocols Error: %s", err.Error()) + continue + } + tool.DeepCopy(&protocols, dst) + server.Protocols = protocols + + nodeStatus, err := l.svcCtx.NodeModel.StatusCache(l.ctx, datum.Id) + if err != nil { + if !errors.Is(err, redis.Nil) { + l.Errorw("[handlerServerStatus] GetNodeStatus Error: ", logger.Field("error", err.Error()), logger.Field("node_id", datum.Id)) + } + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "GetNodeStatus Error") + } + server.Status = types.ServerStatus{ + Mem: nodeStatus.Mem, + Cpu: nodeStatus.Cpu, + Disk: nodeStatus.Disk, + Online: l.handlerServerStatus(datum.Id, protocols), + Status: l.handlerServerStaus(datum.LastReportedAt), + } + list = append(list, server) + } + + return &types.FilterServerListResponse{ + List: list, + Total: total, + }, nil +} + +func (l *FilterServerListLogic) handlerServerStatus(id int64, protocols []types.Protocol) []types.ServerOnlineUser { + result := make([]types.ServerOnlineUser, 0) + + for _, protocol := range protocols { + // query online user + data, err := l.svcCtx.NodeModel.OnlineUserSubscribe(l.ctx, id, protocol.Type) + if err != nil { + if !errors.Is(err, redis.Nil) { + l.Errorw("[handlerServerStatus] OnlineUserSubscribe Error: ", logger.Field("error", err.Error()), logger.Field("node_id", id), logger.Field("protocol", protocol.Type)) + } + continue + } + if len(data) > 0 { + for sub, online := range data { + var ips []types.ServerOnlineIP + for _, ip := range online { + ips = append(ips, types.ServerOnlineIP{ + IP: ip, + Protocol: protocol.Type, + }) + } + + result = append(result, types.ServerOnlineUser{ + IP: ips, + SubscribeId: sub, + }) + } + } + } + // merge same subscribe + var mapResult = make(map[int64]types.ServerOnlineUser) + for _, item := range result { + if exist, ok := mapResult[item.SubscribeId]; ok { + // merge + exist.Traffic += item.Traffic + exist.IP = append(exist.IP, item.IP...) + mapResult[item.SubscribeId] = exist + } else { + // get subscribe info + info, err := l.svcCtx.UserModel.FindOneUserSubscribe(l.ctx, item.SubscribeId) + if err != nil { + if !errors.Is(err, gorm.ErrRecordNotFound) { + l.Errorw("[handlerServerStatus] FindOneSubscribe Error: ", logger.Field("error", err.Error()), logger.Field("subscribe_id", item.SubscribeId)) + } + continue + } + data := types.ServerOnlineUser{ + IP: item.IP, + UserId: info.UserId, + Subscribe: "", + SubscribeId: item.SubscribeId, + Traffic: info.Download + info.Upload, + ExpiredAt: info.ExpireTime.UnixMilli(), + } + if info.Subscribe != nil { + data.Subscribe = info.Subscribe.Name + } + // add new + mapResult[item.SubscribeId] = data + } + } + // convert map to slice + result = make([]types.ServerOnlineUser, 0, len(mapResult)) + for _, item := range mapResult { + result = append(result, item) + } + return result +} + +func (l *FilterServerListLogic) handlerServerStaus(last *time.Time) string { + if last == nil { + return "offline" + } + if time.Since(*last) > time.Minute*5 { + return "offline" + } + if time.Since(*last) > time.Minute*3 { + return "warning" + } + return "online" + +} diff --git a/internal/logic/admin/server/getNodeDetailLogic.go b/internal/logic/admin/server/getNodeDetailLogic.go deleted file mode 100644 index 2feb8fe..0000000 --- a/internal/logic/admin/server/getNodeDetailLogic.go +++ /dev/null @@ -1,43 +0,0 @@ -package server - -import ( - "context" - "encoding/json" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type GetNodeDetailLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -func NewGetNodeDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetNodeDetailLogic { - return &GetNodeDetailLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *GetNodeDetailLogic) GetNodeDetail(req *types.GetDetailRequest) (resp *types.Server, err error) { - detail, err := l.svcCtx.ServerModel.FindOne(l.ctx, req.Id) - if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "get server detail error: %v", err.Error()) - } - resp = &types.Server{} - tool.DeepCopy(resp, detail) - var cfg map[string]interface{} - err = json.Unmarshal([]byte(detail.Config), &cfg) - if err != nil { - cfg = make(map[string]interface{}) - } - resp.Config = cfg - return -} diff --git a/internal/logic/admin/server/getNodeGroupListLogic.go b/internal/logic/admin/server/getNodeGroupListLogic.go deleted file mode 100644 index 6ab53c8..0000000 --- a/internal/logic/admin/server/getNodeGroupListLogic.go +++ /dev/null @@ -1,39 +0,0 @@ -package server - -import ( - "context" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type GetNodeGroupListLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -func NewGetNodeGroupListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetNodeGroupListLogic { - return &GetNodeGroupListLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *GetNodeGroupListLogic) GetNodeGroupList() (resp *types.GetNodeGroupListResponse, err error) { - nodeGroupList, err := l.svcCtx.ServerModel.QueryAllGroup(l.ctx) - if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), err.Error()) - } - nodeGroups := make([]types.ServerGroup, 0) - tool.DeepCopy(&nodeGroups, nodeGroupList) - return &types.GetNodeGroupListResponse{ - Total: int64(len(nodeGroups)), - List: nodeGroups, - }, nil -} diff --git a/internal/logic/admin/server/getNodeListLogic.go b/internal/logic/admin/server/getNodeListLogic.go deleted file mode 100644 index 544c85d..0000000 --- a/internal/logic/admin/server/getNodeListLogic.go +++ /dev/null @@ -1,104 +0,0 @@ -package server - -import ( - "context" - "encoding/json" - "strings" - - "github.com/perfect-panel/server/internal/model/server" - - "github.com/redis/go-redis/v9" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type GetNodeListLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -func NewGetNodeListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetNodeListLogic { - return &GetNodeListLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *GetNodeListLogic) GetNodeList(req *types.GetNodeServerListRequest) (resp *types.GetNodeServerListResponse, err error) { - tags := make([]string, 0) - if req.Tags != "" { - tags = strings.Split(req.Tags, ",") - } - total, list, err := l.svcCtx.ServerModel.FindServerListByFilter(l.ctx, &server.ServerFilter{ - Page: req.Page, - Size: req.Size, - Search: req.Search, - Tags: tags, - Group: req.GroupId, - }) - if err != nil { - l.Errorw("[GetNodeList] Query Database Error: ", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), err.Error()) - } - nodes := make([]types.Server, 0) - for _, v := range list { - node := types.Server{} - tool.DeepCopy(&node, v) - // default relay mode - if node.RelayMode == "" { - node.RelayMode = "none" - } - if len(v.Tags) > 0 { - if strings.Contains(v.Tags, ",") { - node.Tags = strings.Split(v.Tags, ",") - } else { - node.Tags = []string{v.Tags} - } - } - // parse config - var cfg map[string]interface{} - err = json.Unmarshal([]byte(v.Config), &cfg) - if err != nil { - cfg = make(map[string]interface{}) - } - node.Config = cfg - relayNode := make([]types.NodeRelay, 0) - err = json.Unmarshal([]byte(v.RelayNode), &relayNode) - if err != nil { - l.Errorw("[GetNodeList] Unmarshal RelayNode Error: ", logger.Field("error", err.Error()), logger.Field("relayNode", v.RelayNode)) - } - node.RelayNode = relayNode - var status types.NodeStatus - nodeStatus, err := l.svcCtx.NodeCache.GetNodeStatus(l.ctx, v.Id) - if err != nil { - // redis nil is not a Error - if !errors.Is(err, redis.Nil) { - l.Errorw("[GetNodeList] Get Node Status Error: ", logger.Field("error", err.Error())) - } - } else { - onlineUser, err := l.svcCtx.NodeCache.GetNodeOnlineUser(l.ctx, v.Id) - if err != nil { - l.Errorw("[GetNodeList] Get Node Online User Error: ", logger.Field("error", err.Error())) - } else { - status.Online = onlineUser - } - status.Cpu = nodeStatus.Cpu - status.Mem = nodeStatus.Mem - status.Disk = nodeStatus.Disk - status.UpdatedAt = nodeStatus.UpdatedAt - } - node.Status = &status - nodes = append(nodes, node) - } - return &types.GetNodeServerListResponse{ - Total: total, - List: nodes, - }, nil -} diff --git a/internal/logic/admin/server/getNodeTagListLogic.go b/internal/logic/admin/server/getNodeTagListLogic.go deleted file mode 100644 index 36eb9e7..0000000 --- a/internal/logic/admin/server/getNodeTagListLogic.go +++ /dev/null @@ -1,31 +0,0 @@ -package server - -import ( - "context" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" -) - -type GetNodeTagListLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Get node tag list -func NewGetNodeTagListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetNodeTagListLogic { - return &GetNodeTagListLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *GetNodeTagListLogic) GetNodeTagList() (resp *types.GetNodeTagListResponse, err error) { - tags, err := l.svcCtx.ServerModel.FindServerTags(l.ctx) - return &types.GetNodeTagListResponse{ - Tags: tool.RemoveDuplicateElements(tags...), - }, nil -} diff --git a/internal/logic/admin/server/getRuleGroupListLogic.go b/internal/logic/admin/server/getRuleGroupListLogic.go deleted file mode 100644 index c3e1a3f..0000000 --- a/internal/logic/admin/server/getRuleGroupListLogic.go +++ /dev/null @@ -1,54 +0,0 @@ -package server - -import ( - "context" - "strings" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type GetRuleGroupListLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Get rule group list -func NewGetRuleGroupListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetRuleGroupListLogic { - return &GetRuleGroupListLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *GetRuleGroupListLogic) GetRuleGroupList() (resp *types.GetRuleGroupResponse, err error) { - nodeRuleGroupList, err := l.svcCtx.ServerModel.QueryAllRuleGroup(l.ctx) - if err != nil { - l.Errorw("[GetRuleGroupList] Query Database Error: ", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), err.Error()) - } - nodeRuleGroups := make([]types.ServerRuleGroup, len(nodeRuleGroupList)) - for i, v := range nodeRuleGroupList { - nodeRuleGroups[i] = types.ServerRuleGroup{ - Id: v.Id, - Icon: v.Icon, - Name: v.Name, - Type: v.Type, - Tags: strings.Split(v.Tags, ","), - Rules: v.Rules, - Enable: v.Enable, - Default: v.Default, - CreatedAt: v.CreatedAt.UnixMilli(), - UpdatedAt: v.UpdatedAt.UnixMilli(), - } - } - return &types.GetRuleGroupResponse{ - Total: int64(len(nodeRuleGroups)), - List: nodeRuleGroups, - }, nil -} diff --git a/internal/logic/admin/server/getServerProtocolsLogic.go b/internal/logic/admin/server/getServerProtocolsLogic.go new file mode 100644 index 0000000..66519d9 --- /dev/null +++ b/internal/logic/admin/server/getServerProtocolsLogic.go @@ -0,0 +1,49 @@ +package server + +import ( + "context" + + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/tool" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" +) + +type GetServerProtocolsLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// Get Server Protocols +func NewGetServerProtocolsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetServerProtocolsLogic { + return &GetServerProtocolsLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *GetServerProtocolsLogic) GetServerProtocols(req *types.GetServerProtocolsRequest) (resp *types.GetServerProtocolsResponse, err error) { + // find server + data, err := l.svcCtx.NodeModel.FindOneServer(l.ctx, req.Id) + if err != nil { + l.Errorf("[GetServerProtocols] FindOneServer Error: %s", err.Error()) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "[GetServerProtocols] FindOneServer Error: %s", err.Error()) + } + + // handler protocols + var protocols []types.Protocol + dst, err := data.UnmarshalProtocols() + if err != nil { + l.Errorf("[FilterServerList] UnmarshalProtocols Error: %s", err.Error()) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "[FilterServerList] UnmarshalProtocols Error: %s", err.Error()) + } + tool.DeepCopy(&protocols, dst) + + return &types.GetServerProtocolsResponse{ + Protocols: protocols, + }, nil +} diff --git a/internal/logic/admin/server/hasMigrateSeverNodeLogic.go b/internal/logic/admin/server/hasMigrateSeverNodeLogic.go new file mode 100644 index 0000000..128b7f6 --- /dev/null +++ b/internal/logic/admin/server/hasMigrateSeverNodeLogic.go @@ -0,0 +1,52 @@ +package server + +import ( + "context" + + "github.com/perfect-panel/server/internal/model/node" + "github.com/perfect-panel/server/internal/model/server" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" +) + +type HasMigrateSeverNodeLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// NewHasMigrateSeverNodeLogic Check if there is any server or node to migrate +func NewHasMigrateSeverNodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *HasMigrateSeverNodeLogic { + return &HasMigrateSeverNodeLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *HasMigrateSeverNodeLogic) HasMigrateSeverNode() (resp *types.HasMigrateSeverNodeResponse, err error) { + var oldCount, newCount int64 + query := l.svcCtx.DB.WithContext(l.ctx) + + err = query.Model(&server.Server{}).Count(&oldCount).Error + if err != nil { + l.Errorw("[HasMigrateSeverNode] Query Old Server Count Error: ", logger.Field("error", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "[HasMigrateSeverNode] Query Old Server Count Error") + } + err = query.Model(&node.Server{}).Count(&newCount).Error + if err != nil { + l.Errorw("[HasMigrateSeverNode] Query New Server Count Error: ", logger.Field("error", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "[HasMigrateSeverNode] Query New Server Count Error") + } + var shouldMigrate bool + if oldCount != 0 && newCount == 0 { + shouldMigrate = true + } + + return &types.HasMigrateSeverNodeResponse{ + HasMigrate: shouldMigrate, + }, nil +} diff --git a/internal/logic/admin/server/migrateServerNodeLogic.go b/internal/logic/admin/server/migrateServerNodeLogic.go new file mode 100644 index 0000000..eec3960 --- /dev/null +++ b/internal/logic/admin/server/migrateServerNodeLogic.go @@ -0,0 +1,331 @@ +package server + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/perfect-panel/server/internal/model/node" + "github.com/perfect-panel/server/internal/model/server" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" +) + +type MigrateServerNodeLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// NewMigrateServerNodeLogic Migrate server and node data to new database +func NewMigrateServerNodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *MigrateServerNodeLogic { + return &MigrateServerNodeLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *MigrateServerNodeLogic) MigrateServerNode() (resp *types.MigrateServerNodeResponse, err error) { + tx := l.svcCtx.DB.WithContext(l.ctx).Begin() + var oldServers []*server.Server + var newServers []*node.Server + var newNodes []*node.Node + + err = tx.Model(&server.Server{}).Find(&oldServers).Error + if err != nil { + l.Errorw("[MigrateServerNode] Query Old Server List Error: ", logger.Field("error", err.Error())) + return &types.MigrateServerNodeResponse{ + Succee: 0, + Fail: 0, + Message: fmt.Sprintf("Query Old Server List Error: %s", err.Error()), + }, nil + } + for _, oldServer := range oldServers { + data, err := l.adapterServer(oldServer) + if err != nil { + l.Errorw("[MigrateServerNode] Adapter Server Error: ", logger.Field("error", err.Error())) + if resp == nil { + resp = &types.MigrateServerNodeResponse{} + } + resp.Fail++ + if resp.Message == "" { + resp.Message = fmt.Sprintf("Adapter Server Error: %s", err.Error()) + } else { + resp.Message = fmt.Sprintf("%s; Adapter Server Error: %s", resp.Message, err.Error()) + } + continue + } + newServers = append(newServers, data) + + newNode, err := l.adapterNode(oldServer) + if err != nil { + l.Errorw("[MigrateServerNode] Adapter Node Error: ", logger.Field("error", err.Error())) + if resp == nil { + resp = &types.MigrateServerNodeResponse{} + } + resp.Fail++ + if resp.Message == "" { + resp.Message = fmt.Sprintf("Adapter Node Error: %s", err.Error()) + } else { + resp.Message = fmt.Sprintf("%s; Adapter Node Error: %s", resp.Message, err.Error()) + } + continue + } + for _, item := range newNode { + if item.Port == 0 { + protocols, _ := data.UnmarshalProtocols() + if len(protocols) > 0 { + item.Port = protocols[0].Port + } + } + newNodes = append(newNodes, item) + } + } + + if len(newServers) > 0 { + err = tx.Model(&node.Server{}).CreateInBatches(newServers, 20).Error + if err != nil { + tx.Rollback() + l.Errorw("[MigrateServerNode] Insert New Server List Error: ", logger.Field("error", err.Error())) + return &types.MigrateServerNodeResponse{ + Succee: 0, + Fail: uint64(len(newServers)), + Message: fmt.Sprintf("Insert New Server List Error: %s", err.Error()), + }, nil + } + } + if len(newNodes) > 0 { + err = tx.Model(&node.Node{}).CreateInBatches(newNodes, 20).Error + if err != nil { + tx.Rollback() + l.Errorw("[MigrateServerNode] Insert New Node List Error: ", logger.Field("error", err.Error())) + return &types.MigrateServerNodeResponse{ + Succee: uint64(len(newServers)), + Fail: uint64(len(newNodes)), + Message: fmt.Sprintf("Insert New Node List Error: %s", err.Error()), + }, nil + } + } + tx.Commit() + + return &types.MigrateServerNodeResponse{ + Succee: uint64(len(newServers)), + Fail: 0, + Message: fmt.Sprintf("Migrate Success: %d servers and %d nodes", len(newServers), len(newNodes)), + }, nil +} + +func (l *MigrateServerNodeLogic) adapterServer(info *server.Server) (*node.Server, error) { + result := &node.Server{ + Id: info.Id, + Name: info.Name, + Country: info.Country, + City: info.City, + Ratio: info.TrafficRatio, + Address: info.ServerAddr, + Sort: int(info.Sort), + Protocols: "", + } + var protocols []node.Protocol + + switch info.Protocol { + case ShadowSocks: + var src server.Shadowsocks + err := json.Unmarshal([]byte(info.Config), &src) + if err != nil { + return nil, err + } + protocols = append(protocols, node.Protocol{ + Type: "shadowsocks", + Cipher: src.Method, + Port: uint16(src.Port), + ServerKey: src.ServerKey, + }) + case Vmess: + var src server.Vmess + err := json.Unmarshal([]byte(info.Config), &src) + if err != nil { + return nil, err + } + protocol := node.Protocol{ + Type: "vmess", + Port: uint16(src.Port), + Security: src.Security, + SNI: src.SecurityConfig.SNI, + AllowInsecure: src.SecurityConfig.AllowInsecure, + Fingerprint: src.SecurityConfig.Fingerprint, + RealityServerAddr: src.SecurityConfig.RealityServerAddr, + RealityServerPort: src.SecurityConfig.RealityServerPort, + RealityPrivateKey: src.SecurityConfig.RealityPrivateKey, + RealityPublicKey: src.SecurityConfig.RealityPublicKey, + RealityShortId: src.SecurityConfig.RealityShortId, + Transport: src.Transport, + Host: src.TransportConfig.Host, + Path: src.TransportConfig.Path, + ServiceName: src.TransportConfig.ServiceName, + Flow: src.Flow, + } + protocols = append(protocols, protocol) + protocols = append(protocols, protocol) + case Vless: + var src server.Vless + err := json.Unmarshal([]byte(info.Config), &src) + if err != nil { + return nil, err + } + protocol := node.Protocol{ + Type: "vless", + Port: uint16(src.Port), + Security: src.Security, + SNI: src.SecurityConfig.SNI, + AllowInsecure: src.SecurityConfig.AllowInsecure, + Fingerprint: src.SecurityConfig.Fingerprint, + RealityServerAddr: src.SecurityConfig.RealityServerAddr, + RealityServerPort: src.SecurityConfig.RealityServerPort, + RealityPrivateKey: src.SecurityConfig.RealityPrivateKey, + RealityPublicKey: src.SecurityConfig.RealityPublicKey, + RealityShortId: src.SecurityConfig.RealityShortId, + Transport: src.Transport, + Host: src.TransportConfig.Host, + Path: src.TransportConfig.Path, + ServiceName: src.TransportConfig.ServiceName, + Flow: src.Flow, + } + protocols = append(protocols, protocol) + case Trojan: + var src server.Trojan + err := json.Unmarshal([]byte(info.Config), &src) + if err != nil { + return nil, err + } + protocol := node.Protocol{ + Type: "trojan", + Port: uint16(src.Port), + Security: src.Security, + SNI: src.SecurityConfig.SNI, + AllowInsecure: src.SecurityConfig.AllowInsecure, + Fingerprint: src.SecurityConfig.Fingerprint, + RealityServerAddr: src.SecurityConfig.RealityServerAddr, + RealityServerPort: src.SecurityConfig.RealityServerPort, + RealityPrivateKey: src.SecurityConfig.RealityPrivateKey, + RealityPublicKey: src.SecurityConfig.RealityPublicKey, + RealityShortId: src.SecurityConfig.RealityShortId, + Transport: src.Transport, + Host: src.TransportConfig.Host, + Path: src.TransportConfig.Path, + ServiceName: src.TransportConfig.ServiceName, + Flow: src.Flow, + } + protocols = append(protocols, protocol) + case Hysteria2: + var src server.Hysteria2 + err := json.Unmarshal([]byte(info.Config), &src) + if err != nil { + return nil, err + } + protocol := node.Protocol{ + Type: "hysteria2", + Port: uint16(src.Port), + HopPorts: src.HopPorts, + HopInterval: src.HopInterval, + ObfsPassword: src.ObfsPassword, + SNI: src.SecurityConfig.SNI, + AllowInsecure: src.SecurityConfig.AllowInsecure, + Fingerprint: src.SecurityConfig.Fingerprint, + RealityServerAddr: src.SecurityConfig.RealityServerAddr, + RealityServerPort: src.SecurityConfig.RealityServerPort, + RealityPrivateKey: src.SecurityConfig.RealityPrivateKey, + RealityPublicKey: src.SecurityConfig.RealityPublicKey, + RealityShortId: src.SecurityConfig.RealityShortId, + } + protocols = append(protocols, protocol) + case Tuic: + var src server.Tuic + err := json.Unmarshal([]byte(info.Config), &src) + if err != nil { + return nil, err + } + protocol := node.Protocol{ + Type: "tuic", + Port: uint16(src.Port), + DisableSNI: src.DisableSNI, + ReduceRtt: src.ReduceRtt, + UDPRelayMode: src.UDPRelayMode, + CongestionController: src.CongestionController, + SNI: src.SecurityConfig.SNI, + AllowInsecure: src.SecurityConfig.AllowInsecure, + Fingerprint: src.SecurityConfig.Fingerprint, + RealityServerAddr: src.SecurityConfig.RealityServerAddr, + RealityServerPort: src.SecurityConfig.RealityServerPort, + RealityPrivateKey: src.SecurityConfig.RealityPrivateKey, + RealityPublicKey: src.SecurityConfig.RealityPublicKey, + RealityShortId: src.SecurityConfig.RealityShortId, + } + protocols = append(protocols, protocol) + case AnyTLS: + var src server.AnyTLS + err := json.Unmarshal([]byte(info.Config), &src) + if err != nil { + return nil, err + } + protocol := node.Protocol{ + Type: "anytls", + Port: uint16(src.Port), + SNI: src.SecurityConfig.SNI, + AllowInsecure: src.SecurityConfig.AllowInsecure, + Fingerprint: src.SecurityConfig.Fingerprint, + RealityServerAddr: src.SecurityConfig.RealityServerAddr, + RealityServerPort: src.SecurityConfig.RealityServerPort, + RealityPrivateKey: src.SecurityConfig.RealityPrivateKey, + RealityPublicKey: src.SecurityConfig.RealityPublicKey, + RealityShortId: src.SecurityConfig.RealityShortId, + } + protocols = append(protocols, protocol) + } + if len(protocols) > 0 { + err := result.MarshalProtocols(protocols) + if err != nil { + return nil, err + } + } + + return result, nil +} + +func (l *MigrateServerNodeLogic) adapterNode(info *server.Server) ([]*node.Node, error) { + var nodes []*node.Node + enable := true + switch info.RelayMode { + case server.RelayModeNone: + nodes = append(nodes, &node.Node{ + Name: info.Name, + Tags: "", + Port: 0, + Address: info.ServerAddr, + ServerId: info.Id, + Protocol: info.Protocol, + Enabled: &enable, + }) + default: + var relays []server.NodeRelay + err := json.Unmarshal([]byte(info.RelayNode), &relays) + if err != nil { + return nil, err + } + for _, relay := range relays { + nodes = append(nodes, &node.Node{ + Name: relay.Prefix + info.Name, + Tags: "", + Port: uint16(relay.Port), + Address: relay.Host, + ServerId: info.Id, + Protocol: info.Protocol, + Enabled: &enable, + }) + } + } + + return nodes, nil +} diff --git a/internal/logic/admin/server/queryNodeTagLogic.go b/internal/logic/admin/server/queryNodeTagLogic.go new file mode 100644 index 0000000..47e0daf --- /dev/null +++ b/internal/logic/admin/server/queryNodeTagLogic.go @@ -0,0 +1,46 @@ +package server + +import ( + "context" + "strings" + + "github.com/perfect-panel/server/internal/model/node" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/tool" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" +) + +type QueryNodeTagLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// NewQueryNodeTagLogic Query all node tags +func NewQueryNodeTagLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryNodeTagLogic { + return &QueryNodeTagLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *QueryNodeTagLogic) QueryNodeTag() (resp *types.QueryNodeTagResponse, err error) { + + var nodes []*node.Node + if err = l.svcCtx.DB.WithContext(l.ctx).Model(&node.Node{}).Find(&nodes).Error; err != nil { + l.Errorw("[QueryNodeTag] Query Database Error: ", logger.Field("error", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "[QueryNodeTag] Query Database Error") + } + var tags []string + for _, item := range nodes { + tags = append(tags, strings.Split(item.Tags, ",")...) + } + + return &types.QueryNodeTagResponse{ + Tags: tool.RemoveDuplicateElements(tags...), + }, nil +} diff --git a/internal/logic/admin/server/nodeSortLogic.go b/internal/logic/admin/server/resetSortWithNodeLogic.go similarity index 68% rename from internal/logic/admin/server/nodeSortLogic.go rename to internal/logic/admin/server/resetSortWithNodeLogic.go index 1141ca9..3866f54 100644 --- a/internal/logic/admin/server/nodeSortLogic.go +++ b/internal/logic/admin/server/resetSortWithNodeLogic.go @@ -3,36 +3,35 @@ package server import ( "context" - "github.com/perfect-panel/server/internal/model/server" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - "gorm.io/gorm" - + "github.com/perfect-panel/server/internal/model/node" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" + "gorm.io/gorm" ) -type NodeSortLogic struct { +type ResetSortWithNodeLogic struct { logger.Logger ctx context.Context svcCtx *svc.ServiceContext } -// Node sort -func NewNodeSortLogic(ctx context.Context, svcCtx *svc.ServiceContext) *NodeSortLogic { - return &NodeSortLogic{ +// NewResetSortWithNodeLogic Reset node sort +func NewResetSortWithNodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ResetSortWithNodeLogic { + return &ResetSortWithNodeLogic{ Logger: logger.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, } } -func (l *NodeSortLogic) NodeSort(req *types.NodeSortRequest) error { - err := l.svcCtx.ServerModel.Transaction(l.ctx, func(db *gorm.DB) error { +func (l *ResetSortWithNodeLogic) ResetSortWithNode(req *types.ResetSortRequest) error { + err := l.svcCtx.NodeModel.Transaction(l.ctx, func(db *gorm.DB) error { // find all servers id var existingIDs []int64 - db.Model(&server.Server{}).Select("id").Find(&existingIDs) + db.Model(&node.Node{}).Select("id").Find(&existingIDs) // check if the id is valid validIDMap := make(map[int64]bool) for _, id := range existingIDs { @@ -46,12 +45,12 @@ func (l *NodeSortLogic) NodeSort(req *types.NodeSortRequest) error { } } // query all servers - var servers []*server.Server - db.Model(&server.Server{}).Order("sort ASC").Find(&servers) + var servers []*node.Node + db.Model(&node.Node{}).Order("sort ASC").Find(&servers) // create a map of the current sort currentSortMap := make(map[int64]int64) for _, item := range servers { - currentSortMap[item.Id] = item.Sort + currentSortMap[item.Id] = int64(item.Sort) } // new sort map @@ -67,12 +66,12 @@ func (l *NodeSortLogic) NodeSort(req *types.NodeSortRequest) error { } } for _, item := range itemsToUpdate { - s, err := l.svcCtx.ServerModel.FindOne(l.ctx, item.Id) + s, err := l.svcCtx.NodeModel.FindOneNode(l.ctx, item.Id) if err != nil { return err } - s.Sort = item.Sort - if err := l.svcCtx.ServerModel.Update(l.ctx, s, db); err != nil { + s.Sort = int(item.Sort) + if err = l.svcCtx.NodeModel.UpdateNode(l.ctx, s, db); err != nil { l.Errorw("[NodeSort] Update Database Error: ", logger.Field("error", err.Error()), logger.Field("id", item.Id), logger.Field("sort", item.Sort)) return err } diff --git a/internal/logic/admin/server/resetSortWithServerLogic.go b/internal/logic/admin/server/resetSortWithServerLogic.go new file mode 100644 index 0000000..3fbe237 --- /dev/null +++ b/internal/logic/admin/server/resetSortWithServerLogic.go @@ -0,0 +1,86 @@ +package server + +import ( + "context" + + "github.com/perfect-panel/server/internal/model/node" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" + "gorm.io/gorm" +) + +type ResetSortWithServerLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// NewResetSortWithServerLogic Reset server sort +func NewResetSortWithServerLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ResetSortWithServerLogic { + return &ResetSortWithServerLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *ResetSortWithServerLogic) ResetSortWithServer(req *types.ResetSortRequest) error { + err := l.svcCtx.NodeModel.Transaction(l.ctx, func(db *gorm.DB) error { + // find all servers id + var existingIDs []int64 + db.Model(&node.Server{}).Select("id").Find(&existingIDs) + // check if the id is valid + validIDMap := make(map[int64]bool) + for _, id := range existingIDs { + validIDMap[id] = true + } + // check if the sort is valid + var validItems []types.SortItem + for _, item := range req.Sort { + if validIDMap[item.Id] { + validItems = append(validItems, item) + } + } + // query all servers + var servers []*node.Server + db.Model(&node.Server{}).Order("sort ASC").Find(&servers) + // create a map of the current sort + currentSortMap := make(map[int64]int64) + for _, item := range servers { + currentSortMap[item.Id] = int64(item.Sort) + } + + // new sort map + newSortMap := make(map[int64]int64) + for _, item := range validItems { + newSortMap[item.Id] = item.Sort + } + + var itemsToUpdate []types.SortItem + for _, item := range validItems { + if oldSort, exists := currentSortMap[item.Id]; exists && oldSort != item.Sort { + itemsToUpdate = append(itemsToUpdate, item) + } + } + for _, item := range itemsToUpdate { + s, err := l.svcCtx.NodeModel.FindOneServer(l.ctx, item.Id) + if err != nil { + return err + } + s.Sort = int(item.Sort) + if err = l.svcCtx.NodeModel.UpdateServer(l.ctx, s, db); err != nil { + l.Errorw("[NodeSort] Update Database Error: ", logger.Field("error", err.Error()), logger.Field("id", item.Id), logger.Field("sort", item.Sort)) + return err + } + } + return nil + }) + if err != nil { + l.Errorw("[NodeSort] Update Database Error: ", logger.Field("error", err.Error())) + return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), err.Error()) + } + return nil +} diff --git a/internal/logic/admin/server/toggleNodeStatusLogic.go b/internal/logic/admin/server/toggleNodeStatusLogic.go new file mode 100644 index 0000000..04e7244 --- /dev/null +++ b/internal/logic/admin/server/toggleNodeStatusLogic.go @@ -0,0 +1,43 @@ +package server + +import ( + "context" + + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" +) + +type ToggleNodeStatusLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// NewToggleNodeStatusLogic Toggle Node Status +func NewToggleNodeStatusLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ToggleNodeStatusLogic { + return &ToggleNodeStatusLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *ToggleNodeStatusLogic) ToggleNodeStatus(req *types.ToggleNodeStatusRequest) error { + data, err := l.svcCtx.NodeModel.FindOneNode(l.ctx, req.Id) + if err != nil { + l.Errorw("[ToggleNodeStatus] Query Database Error: ", logger.Field("error", err.Error())) + return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "[ToggleNodeStatus] Query Database Error") + } + data.Enabled = req.Enable + + err = l.svcCtx.NodeModel.UpdateNode(l.ctx, data) + if err != nil { + l.Errorw("[ToggleNodeStatus] Update Database Error: ", logger.Field("error", err.Error())) + return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "[ToggleNodeStatus] Update Database Error") + } + + return nil +} diff --git a/internal/logic/admin/server/updateNodeGroupLogic.go b/internal/logic/admin/server/updateNodeGroupLogic.go deleted file mode 100644 index 5df203b..0000000 --- a/internal/logic/admin/server/updateNodeGroupLogic.go +++ /dev/null @@ -1,40 +0,0 @@ -package server - -import ( - "context" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type UpdateNodeGroupLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -func NewUpdateNodeGroupLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateNodeGroupLogic { - return &UpdateNodeGroupLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *UpdateNodeGroupLogic) UpdateNodeGroup(req *types.UpdateNodeGroupRequest) error { - // check server group exist - nodeGroup, err := l.svcCtx.ServerModel.FindOneGroup(l.ctx, req.Id) - if err != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), err.Error()) - } - nodeGroup.Name = req.Name - nodeGroup.Description = req.Description - err = l.svcCtx.ServerModel.UpdateGroup(l.ctx, nodeGroup) - if err != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), err.Error()) - } - return nil -} diff --git a/internal/logic/admin/server/updateNodeLogic.go b/internal/logic/admin/server/updateNodeLogic.go index 3582f12..557e535 100644 --- a/internal/logic/admin/server/updateNodeLogic.go +++ b/internal/logic/admin/server/updateNodeLogic.go @@ -2,12 +2,6 @@ package server import ( "context" - "encoding/json" - "strings" - - "github.com/hibiken/asynq" - "github.com/perfect-panel/server/pkg/device" - queue "github.com/perfect-panel/server/queue/types" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" @@ -23,6 +17,7 @@ type UpdateNodeLogic struct { svcCtx *svc.ServiceContext } +// NewUpdateNodeLogic Update Node func NewUpdateNodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateNodeLogic { return &UpdateNodeLogic{ Logger: logger.WithContext(ctx), @@ -32,108 +27,22 @@ func NewUpdateNodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Update } func (l *UpdateNodeLogic) UpdateNode(req *types.UpdateNodeRequest) error { - // Check server exist - nodeInfo, err := l.svcCtx.ServerModel.FindOne(l.ctx, req.Id) + data, err := l.svcCtx.NodeModel.FindOneNode(l.ctx, req.Id) if err != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find server error: %v", err) + l.Errorw("[UpdateNode] Query Database Error: ", logger.Field("error", err.Error())) + return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "[UpdateNode] Query Database Error") } - tool.DeepCopy(nodeInfo, req, tool.CopyWithIgnoreEmpty(false)) - config, err := json.Marshal(req.Config) - if err != nil { - return err - } - - nodeInfo.Config = string(config) - nodeRelay, err := json.Marshal(req.RelayNode) - if err != nil { - l.Errorw("[UpdateNode] Marshal RelayNode Error: ", logger.Field("error", err.Error())) - return err - } - - // 处理Tags字段 - switch { - case len(req.Tags) > 0: - // 有Tags,进行连接 - nodeInfo.Tags = strings.Join(req.Tags, ",") - default: - // 空数组,清空Tags - nodeInfo.Tags = "" - } - - nodeInfo.City = req.City - nodeInfo.Country = req.Country - - nodeInfo.RelayNode = string(nodeRelay) - if req.Protocol == "vless" { - var cfg types.Vless - if err := json.Unmarshal(config, &cfg); err != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "json.Unmarshal error: %v", err.Error()) - } - if cfg.Security == "reality" && cfg.SecurityConfig.RealityPublicKey == "" { - public, private, err := tool.Curve25519Genkey(false, "") - if err != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "generate curve25519 key error") - } - cfg.SecurityConfig.RealityPublicKey = public - cfg.SecurityConfig.RealityPrivateKey = private - cfg.SecurityConfig.RealityShortId = tool.GenerateShortID(private) - } - if cfg.SecurityConfig.RealityServerAddr == "" { - cfg.SecurityConfig.RealityServerAddr = cfg.SecurityConfig.SNI - } - if cfg.SecurityConfig.RealityServerPort == 0 { - cfg.SecurityConfig.RealityServerPort = 443 - } - config, _ = json.Marshal(cfg) - nodeInfo.Config = string(config) - } else if req.Protocol == "shadowsocks" { - var cfg types.Shadowsocks - if err = json.Unmarshal(config, &cfg); err != nil { - l.Errorf("[CreateNode] Unmarshal Shadowsocks Config Error: %v", err.Error()) - return errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "json.Unmarshal error: %v", err.Error()) - } - if strings.Contains(cfg.Method, "2022") { - var length int - switch cfg.Method { - case "2022-blake3-aes-128-gcm": - length = 16 - default: - length = 32 - } - if len(cfg.ServerKey) != length { - cfg.ServerKey = tool.GenerateCipher(cfg.ServerKey, length) - } - } - config, _ = json.Marshal(cfg) - nodeInfo.Config = string(config) - } - err = l.svcCtx.ServerModel.Update(l.ctx, nodeInfo) + data.Name = req.Name + data.Tags = tool.StringSliceToString(req.Tags) + data.ServerId = req.ServerId + data.Port = req.Port + data.Address = req.Address + data.Protocol = req.Protocol + data.Enabled = req.Enabled + err = l.svcCtx.NodeModel.UpdateNode(l.ctx, data) if err != nil { l.Errorw("[UpdateNode] Update Database Error: ", logger.Field("error", err.Error())) - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "create server error: %v", err) + return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "[UpdateNode] Update Database Error") } - - if req.City == "" || req.Country == "" { - // Marshal the task payload - payload, err := json.Marshal(queue.GetNodeCountry{ - Protocol: nodeInfo.Protocol, - ServerAddr: nodeInfo.ServerAddr, - }) - if err != nil { - l.Errorw("[GetNodeCountry]: Marshal Error", logger.Field("error", err.Error())) - return errors.Wrap(xerr.NewErrCode(xerr.ERROR), "Failed to marshal task payload") - } - // Create a queue task - task := asynq.NewTask(queue.ForthwithGetCountry, payload) - // Enqueue the task - taskInfo, err := l.svcCtx.Queue.Enqueue(task) - if err != nil { - l.Errorw("[GetNodeCountry]: Enqueue Error", logger.Field("error", err.Error()), logger.Field("payload", string(payload))) - return errors.Wrap(xerr.NewErrCode(xerr.ERROR), "Failed to enqueue task") - } - l.Infow("[GetNodeCountry]: Enqueue Success", logger.Field("taskID", taskInfo.ID), logger.Field("payload", string(payload))) - } - - l.svcCtx.DeviceManager.Broadcast(device.SubscribeUpdate) return nil } diff --git a/internal/logic/admin/server/updateRuleGroupLogic.go b/internal/logic/admin/server/updateRuleGroupLogic.go deleted file mode 100644 index 500ba02..0000000 --- a/internal/logic/admin/server/updateRuleGroupLogic.go +++ /dev/null @@ -1,58 +0,0 @@ -package server - -import ( - "context" - "strings" - - "github.com/perfect-panel/server/pkg/tool" - - "github.com/perfect-panel/server/internal/model/server" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" -) - -type UpdateRuleGroupLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// NewUpdateRuleGroupLogic Update rule group -func NewUpdateRuleGroupLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateRuleGroupLogic { - return &UpdateRuleGroupLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *UpdateRuleGroupLogic) UpdateRuleGroup(req *types.UpdateRuleGroupRequest) error { - rs, err := parseAndValidateRules(req.Rules, req.Name) - if err != nil { - return err - } - err = l.svcCtx.ServerModel.UpdateRuleGroup(l.ctx, &server.RuleGroup{ - Id: req.Id, - Icon: req.Icon, - Type: req.Type, - Name: req.Name, - Tags: tool.StringSliceToString(req.Tags), - Rules: strings.Join(rs, "\n"), - Default: req.Default, - Enable: req.Enable, - }) - if err != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), err.Error()) - } - if req.Default { - if err = l.svcCtx.ServerModel.SetDefaultRuleGroup(l.ctx, req.Id); err != nil { - l.Errorf("SetDefaultRuleGroup error: %v", err.Error()) - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), err.Error()) - } - } - return nil -} diff --git a/internal/logic/admin/server/updateServerLogic.go b/internal/logic/admin/server/updateServerLogic.go new file mode 100644 index 0000000..2554f85 --- /dev/null +++ b/internal/logic/admin/server/updateServerLogic.go @@ -0,0 +1,115 @@ +package server + +import ( + "context" + "strings" + + "github.com/perfect-panel/server/internal/model/node" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/ip" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/tool" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" +) + +type UpdateServerLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// NewUpdateServerLogic Update Server +func NewUpdateServerLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateServerLogic { + return &UpdateServerLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *UpdateServerLogic) UpdateServer(req *types.UpdateServerRequest) error { + data, err := l.svcCtx.NodeModel.FindOneServer(l.ctx, req.Id) + if err != nil { + l.Errorf("[UpdateServer] FindOneServer Error: %v", err.Error()) + return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find server error: %v", err.Error()) + } + data.Name = req.Name + data.Country = req.Country + data.City = req.City + data.Ratio = req.Ratio + // only update address when it's different + if req.Address != data.Address { + // query server ip location + result, err := ip.GetRegionByIp(req.Address) + if err != nil { + l.Errorf("[UpdateServer] GetRegionByIp Error: %v", err.Error()) + } else { + data.City = result.City + data.Country = result.Country + } + // update address + data.Address = req.Address + } + protocols := make([]node.Protocol, 0) + for _, item := range req.Protocols { + if item.Type == "" { + return errors.Wrapf(xerr.NewErrCodeMsg(xerr.InvalidParams, "protocols type is empty"), "protocols type is empty") + } + var protocol node.Protocol + tool.DeepCopy(&protocol, item) + + // VLESS Reality Key Generation + if protocol.Type == "vless" { + if protocol.Security == "reality" { + if protocol.RealityPublicKey == "" { + public, private, err := tool.Curve25519Genkey(false, "") + if err != nil { + l.Errorf("[CreateServer] Generate Reality Key Error: %v", err.Error()) + return errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "generate reality key error: %v", err) + } + protocol.RealityPublicKey = public + protocol.RealityPrivateKey = private + protocol.RealityShortId = tool.GenerateShortID(private) + } + if protocol.RealityServerAddr == "" { + protocol.RealityServerAddr = protocol.SNI + } + if protocol.RealityServerPort == 0 { + protocol.RealityServerPort = 443 + } + } + + } + // ShadowSocks 2022 Key Generation + if protocol.Type == "shadowsocks" { + if strings.Contains(protocol.Cipher, "2022") { + var length int + switch protocol.Cipher { + case "2022-blake3-aes-128-gcm": + length = 16 + default: + length = 32 + } + if len(protocol.ServerKey) != length { + protocol.ServerKey = tool.GenerateCipher(protocol.ServerKey, length) + } + } + } + protocols = append(protocols, protocol) + } + err = data.MarshalProtocols(protocols) + if err != nil { + l.Errorf("[UpdateServer] Marshal Protocols Error: %v", err.Error()) + return errors.Wrapf(xerr.NewErrCodeMsg(xerr.InvalidParams, "protocols marshal error"), "protocols marshal error: %v", err) + } + + err = l.svcCtx.NodeModel.UpdateServer(l.ctx, data) + if err != nil { + l.Errorf("[UpdateServer] UpdateServer Error: %v", err.Error()) + return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "update server error: %v", err.Error()) + } + + return nil +} diff --git a/internal/logic/admin/subscribe/createSubscribeLogic.go b/internal/logic/admin/subscribe/createSubscribeLogic.go index 729bf5b..bf50d6a 100644 --- a/internal/logic/admin/subscribe/createSubscribeLogic.go +++ b/internal/logic/admin/subscribe/createSubscribeLogic.go @@ -37,6 +37,7 @@ func (l *CreateSubscribeLogic) CreateSubscribe(req *types.CreateSubscribeRequest sub := &subscribe.Subscribe{ Id: 0, Name: req.Name, + Language: req.Language, Description: req.Description, UnitPrice: req.UnitPrice, UnitTime: req.UnitTime, @@ -47,9 +48,8 @@ func (l *CreateSubscribeLogic) CreateSubscribe(req *types.CreateSubscribeRequest SpeedLimit: req.SpeedLimit, DeviceLimit: req.DeviceLimit, Quota: req.Quota, - GroupId: req.GroupId, - ServerGroup: tool.Int64SliceToString(req.ServerGroup), - Server: tool.Int64SliceToString(req.Server), + Nodes: tool.Int64SliceToString(req.Nodes), + NodeTags: tool.StringSliceToString(req.NodeTags), Show: req.Show, Sell: req.Sell, Sort: 0, diff --git a/internal/logic/admin/subscribe/getSubscribeDetailsLogic.go b/internal/logic/admin/subscribe/getSubscribeDetailsLogic.go index 856cbf7..6defdf1 100644 --- a/internal/logic/admin/subscribe/getSubscribeDetailsLogic.go +++ b/internal/logic/admin/subscribe/getSubscribeDetailsLogic.go @@ -3,6 +3,7 @@ package subscribe import ( "context" "encoding/json" + "strings" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" @@ -41,7 +42,7 @@ func (l *GetSubscribeDetailsLogic) GetSubscribeDetails(req *types.GetSubscribeDe l.Logger.Error("[GetSubscribeDetailsLogic] JSON unmarshal failed: ", logger.Field("error", err.Error()), logger.Field("discount", sub.Discount)) } } - resp.Server = tool.StringToInt64Slice(sub.Server) - resp.ServerGroup = tool.StringToInt64Slice(sub.ServerGroup) + resp.Nodes = tool.StringToInt64Slice(sub.Nodes) + resp.NodeTags = strings.Split(sub.NodeTags, ",") return resp, nil } diff --git a/internal/logic/admin/subscribe/getSubscribeListLogic.go b/internal/logic/admin/subscribe/getSubscribeListLogic.go index 7168afb..e8c7866 100644 --- a/internal/logic/admin/subscribe/getSubscribeListLogic.go +++ b/internal/logic/admin/subscribe/getSubscribeListLogic.go @@ -3,7 +3,9 @@ package subscribe import ( "context" "encoding/json" + "strings" + "github.com/perfect-panel/server/internal/model/subscribe" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" @@ -28,7 +30,12 @@ func NewGetSubscribeListLogic(ctx context.Context, svcCtx *svc.ServiceContext) * } func (l *GetSubscribeListLogic) GetSubscribeList(req *types.GetSubscribeListRequest) (resp *types.GetSubscribeListResponse, err error) { - total, list, err := l.svcCtx.SubscribeModel.QuerySubscribeListByPage(l.ctx, int(req.Page), int(req.Size), req.GroupId, req.Search) + total, list, err := l.svcCtx.SubscribeModel.FilterList(l.ctx, &subscribe.FilterParams{ + Page: int(req.Page), + Size: int(req.Size), + Language: req.Language, + Search: req.Search, + }) if err != nil { l.Logger.Error("[GetSubscribeListLogic] get subscribe list failed: ", logger.Field("error", err.Error())) return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "get subscribe list failed: %v", err.Error()) @@ -47,8 +54,8 @@ func (l *GetSubscribeListLogic) GetSubscribeList(req *types.GetSubscribeListRequ l.Logger.Error("[GetSubscribeListLogic] JSON unmarshal failed: ", logger.Field("error", err.Error()), logger.Field("discount", item.Discount)) } } - sub.Server = tool.StringToInt64Slice(item.Server) - sub.ServerGroup = tool.StringToInt64Slice(item.ServerGroup) + sub.Nodes = tool.StringToInt64Slice(item.Nodes) + sub.NodeTags = strings.Split(item.NodeTags, ",") resultList = append(resultList, sub) } @@ -59,8 +66,8 @@ func (l *GetSubscribeListLogic) GetSubscribeList(req *types.GetSubscribeListRequ } for i, item := range resultList { - if subscribe, ok := subscribeMaps[item.Id]; ok { - resultList[i].Sold = subscribe + if sub, ok := subscribeMaps[item.Id]; ok { + resultList[i].Sold = sub } } diff --git a/internal/logic/admin/subscribe/subscribeSortLogic.go b/internal/logic/admin/subscribe/subscribeSortLogic.go index bbdeec9..9a5cb5b 100644 --- a/internal/logic/admin/subscribe/subscribeSortLogic.go +++ b/internal/logic/admin/subscribe/subscribeSortLogic.go @@ -3,6 +3,7 @@ package subscribe import ( "context" + "github.com/perfect-panel/server/internal/model/subscribe" "github.com/perfect-panel/server/pkg/xerr" "github.com/pkg/errors" "gorm.io/gorm" @@ -40,7 +41,11 @@ func (l *SubscribeSortLogic) SubscribeSort(req *types.SubscribeSortRequest) erro l.Logger.Error("[SubscribeSortLogic] query subscribe list by ids error: ", logger.Field("error", err.Error())) return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query subscribe list by ids error: %v", err.Error()) } - subs, err := l.svcCtx.SubscribeModel.QuerySubscribeListByIds(l.ctx, ids) + _, subs, err := l.svcCtx.SubscribeModel.FilterList(l.ctx, &subscribe.FilterParams{ + Page: 1, + Size: 9999, + Ids: ids, + }) if err != nil { l.Logger.Error("[SubscribeSortLogic] query subscribe list by ids error: ", logger.Field("error", err.Error())) return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query subscribe list by ids error: %v", err.Error()) diff --git a/internal/logic/admin/subscribe/updateSubscribeLogic.go b/internal/logic/admin/subscribe/updateSubscribeLogic.go index e04e4ef..060af5a 100644 --- a/internal/logic/admin/subscribe/updateSubscribeLogic.go +++ b/internal/logic/admin/subscribe/updateSubscribeLogic.go @@ -45,6 +45,7 @@ func (l *UpdateSubscribeLogic) UpdateSubscribe(req *types.UpdateSubscribeRequest sub := &subscribe.Subscribe{ Id: req.Id, Name: req.Name, + Language: req.Language, Description: req.Description, UnitPrice: req.UnitPrice, UnitTime: req.UnitTime, @@ -55,9 +56,8 @@ func (l *UpdateSubscribeLogic) UpdateSubscribe(req *types.UpdateSubscribeRequest SpeedLimit: req.SpeedLimit, DeviceLimit: req.DeviceLimit, Quota: req.Quota, - GroupId: req.GroupId, - ServerGroup: tool.Int64SliceToString(req.ServerGroup), - Server: tool.Int64SliceToString(req.Server), + Nodes: tool.Int64SliceToString(req.Nodes), + NodeTags: tool.StringSliceToString(req.NodeTags), Show: req.Show, Sell: req.Sell, Sort: req.Sort, diff --git a/internal/logic/admin/system/createApplicationLogic.go b/internal/logic/admin/system/createApplicationLogic.go deleted file mode 100644 index 6191edd..0000000 --- a/internal/logic/admin/system/createApplicationLogic.go +++ /dev/null @@ -1,125 +0,0 @@ -package system - -import ( - "context" - - "github.com/perfect-panel/server/internal/model/application" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type CreateApplicationLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -func NewCreateApplicationLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateApplicationLogic { - return &CreateApplicationLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *CreateApplicationLogic) CreateApplication(req *types.CreateApplicationRequest) error { - var ios []application.ApplicationVersion - if len(req.Platform.IOS) > 0 { - for _, ios_ := range req.Platform.IOS { - ios = append(ios, application.ApplicationVersion{ - Url: ios_.Url, - Version: ios_.Version, - Platform: "ios", - IsDefault: ios_.IsDefault, - Description: ios_.Description, - }) - } - } - - var mac []application.ApplicationVersion - if len(req.Platform.MacOS) > 0 { - for _, mac_ := range req.Platform.MacOS { - mac = append(mac, application.ApplicationVersion{ - Url: mac_.Url, - Version: mac_.Version, - Platform: "macos", - IsDefault: mac_.IsDefault, - Description: mac_.Description, - }) - } - } - - var linux []application.ApplicationVersion - if len(req.Platform.Linux) > 0 { - for _, linux_ := range req.Platform.Linux { - linux = append(linux, application.ApplicationVersion{ - Url: linux_.Url, - Version: linux_.Version, - Platform: "linux", - IsDefault: linux_.IsDefault, - Description: linux_.Description, - }) - } - } - - var android []application.ApplicationVersion - if len(req.Platform.Android) > 0 { - for _, android_ := range req.Platform.Android { - android = append(android, application.ApplicationVersion{ - Url: android_.Url, - Version: android_.Version, - Platform: "android", - IsDefault: android_.IsDefault, - Description: android_.Description, - }) - } - } - - var windows []application.ApplicationVersion - if len(req.Platform.Windows) > 0 { - for _, windows_ := range req.Platform.Windows { - windows = append(windows, application.ApplicationVersion{ - Url: windows_.Url, - Version: windows_.Version, - Platform: "windows", - IsDefault: windows_.IsDefault, - Description: windows_.Description, - }) - } - } - - var harmony []application.ApplicationVersion - if len(req.Platform.Harmony) > 0 { - for _, harmony_ := range req.Platform.Harmony { - harmony = append(harmony, application.ApplicationVersion{ - Url: harmony_.Url, - Version: harmony_.Version, - Platform: "harmony", - IsDefault: harmony_.IsDefault, - Description: harmony_.Description, - }) - } - } - var applicationVersions []application.ApplicationVersion - applicationVersions = append(applicationVersions, ios...) - applicationVersions = append(applicationVersions, mac...) - applicationVersions = append(applicationVersions, linux...) - applicationVersions = append(applicationVersions, android...) - applicationVersions = append(applicationVersions, windows...) - applicationVersions = append(applicationVersions, harmony...) - app := application.Application{ - Name: req.Name, - Icon: req.Icon, - SubscribeType: req.SubscribeType, - ApplicationVersions: applicationVersions, - } - err := l.svcCtx.ApplicationModel.Insert(l.ctx, &app) - if err != nil { - l.Errorw("[CreateApplicationLogic] create application error: ", logger.Field("error", err.Error())) - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "create application error: %v", err) - } - return nil -} diff --git a/internal/logic/admin/system/createApplicationVersionLogic.go b/internal/logic/admin/system/createApplicationVersionLogic.go deleted file mode 100644 index 34a8970..0000000 --- a/internal/logic/admin/system/createApplicationVersionLogic.go +++ /dev/null @@ -1,44 +0,0 @@ -package system - -import ( - "context" - - "github.com/perfect-panel/server/internal/model/application" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type CreateApplicationVersionLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Create application version -func NewCreateApplicationVersionLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateApplicationVersionLogic { - return &CreateApplicationVersionLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *CreateApplicationVersionLogic) CreateApplicationVersion(req *types.CreateApplicationVersionRequest) error { - create := &application.ApplicationVersion{ - Url: req.Url, - Platform: req.Platform, - Version: req.Version, - Description: req.Description, - IsDefault: req.IsDefault, - ApplicationId: req.ApplicationId, - } - err := l.svcCtx.ApplicationModel.InsertVersion(l.ctx, create) - if err != nil { - l.Errorw("[CreateApplicationVersion] create application version error: ", logger.Field("error", err.Error())) - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "create application version error: %v", err) - } - return nil -} diff --git a/internal/logic/admin/system/deleteApplicationLogic.go b/internal/logic/admin/system/deleteApplicationLogic.go deleted file mode 100644 index 6bd3836..0000000 --- a/internal/logic/admin/system/deleteApplicationLogic.go +++ /dev/null @@ -1,35 +0,0 @@ -package system - -import ( - "context" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type DeleteApplicationLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -func NewDeleteApplicationLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteApplicationLogic { - return &DeleteApplicationLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *DeleteApplicationLogic) DeleteApplication(req *types.DeleteApplicationRequest) error { - // delete application - err := l.svcCtx.ApplicationModel.Delete(l.ctx, req.Id) - if err != nil { - l.Errorw("[DeleteApplicationLogic] delete application error: ", logger.Field("error", err.Error())) - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseDeletedError), "delete application error: %v", err.Error()) - } - return nil -} diff --git a/internal/logic/admin/system/deleteApplicationVersionLogic.go b/internal/logic/admin/system/deleteApplicationVersionLogic.go deleted file mode 100644 index 822d764..0000000 --- a/internal/logic/admin/system/deleteApplicationVersionLogic.go +++ /dev/null @@ -1,36 +0,0 @@ -package system - -import ( - "context" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type DeleteApplicationVersionLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Delete application -func NewDeleteApplicationVersionLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteApplicationVersionLogic { - return &DeleteApplicationVersionLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *DeleteApplicationVersionLogic) DeleteApplicationVersion(req *types.DeleteApplicationVersionRequest) error { - // delete application - err := l.svcCtx.ApplicationModel.DeleteVersion(l.ctx, req.Id) - if err != nil { - l.Errorw("[DeleteApplicationVersion] delete application version error: ", logger.Field("error", err.Error())) - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseDeletedError), "delete application version error: %v", err.Error()) - } - return nil -} diff --git a/internal/logic/admin/system/getApplicationConfigLogic.go b/internal/logic/admin/system/getApplicationConfigLogic.go deleted file mode 100644 index 3d3759f..0000000 --- a/internal/logic/admin/system/getApplicationConfigLogic.go +++ /dev/null @@ -1,49 +0,0 @@ -package system - -import ( - "context" - "strings" - - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - "gorm.io/gorm" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" -) - -type GetApplicationConfigLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// get application config -func NewGetApplicationConfigLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetApplicationConfigLogic { - return &GetApplicationConfigLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *GetApplicationConfigLogic) GetApplicationConfig() (resp *types.ApplicationConfig, err error) { - resp = &types.ApplicationConfig{} - appConfig, err := l.svcCtx.ApplicationModel.FindOneConfig(l.ctx, 1) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - err = nil - return - } - l.Errorw("[GetApplicationConfig] Database Error", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "get app config error: %v", err.Error()) - } - resp.AppId = appConfig.AppId - resp.EncryptionKey = appConfig.EncryptionKey - resp.EncryptionMethod = appConfig.EncryptionMethod - resp.Domains = strings.Split(appConfig.Domains, ";") - resp.StartupPicture = appConfig.StartupPicture - resp.StartupPictureSkipTime = appConfig.StartupPictureSkipTime - return -} diff --git a/internal/logic/admin/system/getApplicationLogic.go b/internal/logic/admin/system/getApplicationLogic.go deleted file mode 100644 index dfb6ab0..0000000 --- a/internal/logic/admin/system/getApplicationLogic.go +++ /dev/null @@ -1,113 +0,0 @@ -package system - -import ( - "context" - - "github.com/perfect-panel/server/internal/model/application" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - "gorm.io/gorm" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" -) - -type GetApplicationLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Get application -func NewGetApplicationLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetApplicationLogic { - return &GetApplicationLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *GetApplicationLogic) GetApplication() (resp *types.ApplicationResponse, err error) { - resp = &types.ApplicationResponse{} - var applications []*application.Application - err = l.svcCtx.ApplicationModel.Transaction(l.ctx, func(tx *gorm.DB) (err error) { - return tx.Model(applications).Preload("ApplicationVersions").Find(&applications).Error - }) - if err != nil { - l.Errorw("[GetApplicationLogic] get application error: ", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "get application error: %v", err.Error()) - } - - if len(applications) == 0 { - return resp, nil - } - - for _, app := range applications { - applicationResponse := types.ApplicationResponseInfo{ - Id: app.Id, - Name: app.Name, - Icon: app.Icon, - Description: app.Description, - SubscribeType: app.SubscribeType, - } - applicationVersions := app.ApplicationVersions - if len(applicationVersions) != 0 { - for _, applicationVersion := range applicationVersions { - switch applicationVersion.Platform { - case "ios": - applicationResponse.Platform.IOS = append(applicationResponse.Platform.IOS, &types.ApplicationVersion{ - Id: applicationVersion.Id, - Url: applicationVersion.Url, - Version: applicationVersion.Version, - IsDefault: applicationVersion.IsDefault, - Description: applicationVersion.Description, - }) - case "macos": - applicationResponse.Platform.MacOS = append(applicationResponse.Platform.MacOS, &types.ApplicationVersion{ - Id: applicationVersion.Id, - Url: applicationVersion.Url, - Version: applicationVersion.Version, - IsDefault: applicationVersion.IsDefault, - Description: applicationVersion.Description, - }) - case "linux": - applicationResponse.Platform.Linux = append(applicationResponse.Platform.Linux, &types.ApplicationVersion{ - Id: applicationVersion.Id, - Url: applicationVersion.Url, - Version: applicationVersion.Version, - IsDefault: applicationVersion.IsDefault, - Description: applicationVersion.Description, - }) - case "android": - applicationResponse.Platform.Android = append(applicationResponse.Platform.Android, &types.ApplicationVersion{ - Id: applicationVersion.Id, - Url: applicationVersion.Url, - Version: applicationVersion.Version, - IsDefault: applicationVersion.IsDefault, - Description: applicationVersion.Description, - }) - case "windows": - applicationResponse.Platform.Windows = append(applicationResponse.Platform.Windows, &types.ApplicationVersion{ - Id: applicationVersion.Id, - Url: applicationVersion.Url, - Version: applicationVersion.Version, - IsDefault: applicationVersion.IsDefault, - Description: applicationVersion.Description, - }) - case "harmony": - applicationResponse.Platform.Harmony = append(applicationResponse.Platform.Harmony, &types.ApplicationVersion{ - Id: applicationVersion.Id, - Url: applicationVersion.Url, - Version: applicationVersion.Version, - IsDefault: applicationVersion.IsDefault, - Description: applicationVersion.Description, - }) - } - } - } - resp.Applications = append(resp.Applications, applicationResponse) - } - - return -} diff --git a/internal/logic/admin/system/getSubscribeTypeLogic.go b/internal/logic/admin/system/getSubscribeTypeLogic.go deleted file mode 100644 index b9309e6..0000000 --- a/internal/logic/admin/system/getSubscribeTypeLogic.go +++ /dev/null @@ -1,42 +0,0 @@ -package system - -import ( - "context" - - "github.com/perfect-panel/server/internal/model/subscribeType" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type GetSubscribeTypeLogic struct { - ctx context.Context - svcCtx *svc.ServiceContext - logger.Logger -} - -func NewGetSubscribeTypeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetSubscribeTypeLogic { - return &GetSubscribeTypeLogic{ - ctx: ctx, - svcCtx: svcCtx, - Logger: logger.WithContext(ctx), - } -} - -func (l *GetSubscribeTypeLogic) GetSubscribeType() (resp *types.SubscribeType, err error) { - var list []*subscribeType.SubscribeType - err = l.svcCtx.DB.Model(&subscribeType.SubscribeType{}).Find(&list).Error - if err != nil { - l.Errorw("[GetSubscribeType] get subscribe type failed", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "get subscribe type failed: %v", err) - } - typeList := make([]string, 0) - for _, item := range list { - typeList = append(typeList, item.Name) - } - return &types.SubscribeType{ - SubscribeTypes: typeList, - }, nil -} diff --git a/internal/logic/admin/system/updateApplicationConfigLogic.go b/internal/logic/admin/system/updateApplicationConfigLogic.go deleted file mode 100644 index 915aa38..0000000 --- a/internal/logic/admin/system/updateApplicationConfigLogic.go +++ /dev/null @@ -1,45 +0,0 @@ -package system - -import ( - "context" - "strings" - - "github.com/perfect-panel/server/internal/model/application" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type UpdateApplicationConfigLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// update application config -func NewUpdateApplicationConfigLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateApplicationConfigLogic { - return &UpdateApplicationConfigLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *UpdateApplicationConfigLogic) UpdateApplicationConfig(req *types.ApplicationConfig) error { - err := l.svcCtx.ApplicationModel.UpdateConfig(l.ctx, &application.ApplicationConfig{ - Id: 1, - AppId: req.AppId, - EncryptionKey: req.EncryptionKey, - EncryptionMethod: req.EncryptionMethod, - Domains: strings.Join(req.Domains, ";"), - StartupPicture: req.StartupPicture, - StartupPictureSkipTime: req.StartupPictureSkipTime, - }) - if err != nil { - l.Errorw("[UpdateApplicationConfig] Database Error", logger.Field("error", err.Error())) - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "update app config error: %v", err.Error()) - } - return nil -} diff --git a/internal/logic/admin/system/updateApplicationLogic.go b/internal/logic/admin/system/updateApplicationLogic.go deleted file mode 100644 index f867ab8..0000000 --- a/internal/logic/admin/system/updateApplicationLogic.go +++ /dev/null @@ -1,149 +0,0 @@ -package system - -import ( - "context" - - "github.com/perfect-panel/server/internal/model/application" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - "gorm.io/gorm" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" -) - -type UpdateApplicationLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -func NewUpdateApplicationLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateApplicationLogic { - return &UpdateApplicationLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *UpdateApplicationLogic) UpdateApplication(req *types.UpdateApplicationRequest) error { - - // find application - app, err := l.svcCtx.ApplicationModel.FindOne(l.ctx, req.Id) - if err != nil { - l.Errorw("[UpdateApplication] find application error", logger.Field("error", err.Error())) - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find application error: %v", err.Error()) - } - app.Name = req.Name - app.Icon = req.Icon - app.SubscribeType = req.SubscribeType - app.Description = req.Description - - var ios []application.ApplicationVersion - if len(req.Platform.IOS) > 0 { - for _, ios_ := range req.Platform.IOS { - ios = append(ios, application.ApplicationVersion{ - Url: ios_.Url, - Version: ios_.Version, - Platform: "ios", - IsDefault: ios_.IsDefault, - Description: ios_.Description, - ApplicationId: app.Id, - }) - } - } - - var mac []application.ApplicationVersion - if len(req.Platform.MacOS) > 0 { - for _, mac_ := range req.Platform.MacOS { - mac = append(mac, application.ApplicationVersion{ - Url: mac_.Url, - Version: mac_.Version, - Platform: "macos", - IsDefault: mac_.IsDefault, - Description: mac_.Description, - ApplicationId: app.Id, - }) - } - } - - var linux []application.ApplicationVersion - if len(req.Platform.Linux) > 0 { - for _, linux_ := range req.Platform.Linux { - linux = append(linux, application.ApplicationVersion{ - Url: linux_.Url, - Version: linux_.Version, - Platform: "linux", - IsDefault: linux_.IsDefault, - Description: linux_.Description, - ApplicationId: app.Id, - }) - } - } - - var android []application.ApplicationVersion - if len(req.Platform.Android) > 0 { - for _, android_ := range req.Platform.Android { - android = append(android, application.ApplicationVersion{ - Url: android_.Url, - Version: android_.Version, - Platform: "android", - IsDefault: android_.IsDefault, - Description: android_.Description, - ApplicationId: app.Id, - }) - } - } - - var windows []application.ApplicationVersion - if len(req.Platform.Windows) > 0 { - for _, windows_ := range req.Platform.Windows { - windows = append(windows, application.ApplicationVersion{ - Url: windows_.Url, - Version: windows_.Version, - Platform: "windows", - IsDefault: windows_.IsDefault, - Description: windows_.Description, - ApplicationId: app.Id, - }) - } - } - - var harmony []application.ApplicationVersion - if len(req.Platform.Harmony) > 0 { - for _, harmony_ := range req.Platform.Harmony { - harmony = append(harmony, application.ApplicationVersion{ - Url: harmony_.Url, - Version: harmony_.Version, - Platform: "harmony", - IsDefault: harmony_.IsDefault, - Description: harmony_.Description, - ApplicationId: app.Id, - }) - } - } - var applicationVersions []application.ApplicationVersion - applicationVersions = append(applicationVersions, ios...) - applicationVersions = append(applicationVersions, mac...) - applicationVersions = append(applicationVersions, linux...) - applicationVersions = append(applicationVersions, android...) - applicationVersions = append(applicationVersions, windows...) - applicationVersions = append(applicationVersions, harmony...) - app.ApplicationVersions = applicationVersions - err = l.svcCtx.ApplicationModel.Transaction(l.ctx, func(db *gorm.DB) error { - - if err = db.Where("application_id = ?", app.Id).Delete(&application.ApplicationVersion{}).Error; err != nil { - return err - } - if err = db.Create(&applicationVersions).Error; err != nil { - return err - } - return db.Save(app).Error - }) - if err != nil { - l.Errorw("[UpdateApplication] update application error", logger.Field("error", err.Error())) - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "update application error: %v", err.Error()) - } - return nil -} diff --git a/internal/logic/admin/system/updateApplicationVersionLogic.go b/internal/logic/admin/system/updateApplicationVersionLogic.go deleted file mode 100644 index 4730ba4..0000000 --- a/internal/logic/admin/system/updateApplicationVersionLogic.go +++ /dev/null @@ -1,45 +0,0 @@ -package system - -import ( - "context" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type UpdateApplicationVersionLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Update application version -func NewUpdateApplicationVersionLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateApplicationVersionLogic { - return &UpdateApplicationVersionLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *UpdateApplicationVersionLogic) UpdateApplicationVersion(req *types.UpdateApplicationVersionRequest) error { - // find application - app, err := l.svcCtx.ApplicationModel.FindOneVersion(l.ctx, req.Id) - if err != nil { - l.Errorw("[UpdateApplicationVersion] find application version error", logger.Field("error", err.Error())) - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find application error: %v", err.Error()) - } - app.Url = req.Url - app.Version = req.Version - app.Description = req.Description - app.IsDefault = req.IsDefault - err = l.svcCtx.ApplicationModel.UpdateVersion(l.ctx, app) - if err != nil { - l.Errorw("[UpdateApplicationVersion] update application version error", logger.Field("error", err.Error())) - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "update application version error: %v", err.Error()) - } - return nil -} diff --git a/internal/logic/admin/user/createUserLogic.go b/internal/logic/admin/user/createUserLogic.go index 0bfdf9f..5f6c858 100644 --- a/internal/logic/admin/user/createUserLogic.go +++ b/internal/logic/admin/user/createUserLogic.go @@ -39,10 +39,12 @@ func (l *CreateUserLogic) CreateUser(req *types.CreateUserRequest) error { } pwd := tool.EncodePassWord(req.Password) newUser := &user.User{ - Password: pwd, - ReferCode: req.ReferCode, - Balance: req.Balance, - IsAdmin: &req.IsAdmin, + Password: pwd, + ReferralPercentage: req.ReferralPercentage, + OnlyFirstPurchase: &req.OnlyFirstPurchase, + ReferCode: req.ReferCode, + Balance: req.Balance, + IsAdmin: &req.IsAdmin, } var ams []user.AuthMethods diff --git a/internal/logic/admin/user/getUserListLogic.go b/internal/logic/admin/user/getUserListLogic.go index 2546568..3859f76 100644 --- a/internal/logic/admin/user/getUserListLogic.go +++ b/internal/logic/admin/user/getUserListLogic.go @@ -41,20 +41,20 @@ func (l *GetUserListLogic) GetUserList(req *types.GetUserListRequest) (*types.Ge userRespList := make([]types.User, 0, len(list)) for _, item := range list { - var user types.User - tool.DeepCopy(&user, item) + var u types.User + tool.DeepCopy(&u, item) // 处理 AuthMethods - authMethods := make([]types.UserAuthMethod, len(user.AuthMethods)) // 直接创建目标 slice - for i, method := range user.AuthMethods { + authMethods := make([]types.UserAuthMethod, len(u.AuthMethods)) // 直接创建目标 slice + for i, method := range u.AuthMethods { tool.DeepCopy(&authMethods[i], method) if method.AuthType == "mobile" { authMethods[i].AuthIdentifier = phone.FormatToInternational(method.AuthIdentifier) } } - user.AuthMethods = authMethods + u.AuthMethods = authMethods - userRespList = append(userRespList, user) + userRespList = append(userRespList, u) } return &types.GetUserListResponse{ diff --git a/internal/logic/admin/user/getUserLoginLogsLogic.go b/internal/logic/admin/user/getUserLoginLogsLogic.go index f70fd24..afaba61 100644 --- a/internal/logic/admin/user/getUserLoginLogsLogic.go +++ b/internal/logic/admin/user/getUserLoginLogsLogic.go @@ -3,11 +3,10 @@ package user import ( "context" - "github.com/perfect-panel/server/internal/model/user" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" "github.com/perfect-panel/server/pkg/xerr" "github.com/pkg/errors" ) @@ -28,15 +27,34 @@ func NewGetUserLoginLogsLogic(ctx context.Context, svcCtx *svc.ServiceContext) * } func (l *GetUserLoginLogsLogic) GetUserLoginLogs(req *types.GetUserLoginLogsRequest) (resp *types.GetUserLoginLogsResponse, err error) { - data, total, err := l.svcCtx.UserModel.FilterLoginLogList(l.ctx, req.Page, req.Size, &user.LoginLogFilterParams{ - UserId: req.UserId, + data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: req.Page, + Size: req.Size, + Type: log.TypeLogin.Uint8(), + ObjectID: req.UserId, }) if err != nil { l.Errorw("[GetUserLoginLogs] get user login logs failed", logger.Field("error", err.Error()), logger.Field("request", req)) return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "get user login logs failed: %v", err.Error()) } var list []types.UserLoginLog - tool.DeepCopy(&list, data) + + for _, datum := range data { + var content log.Login + if err = content.Unmarshal([]byte(datum.Content)); err != nil { + l.Errorf("[GetUserLoginLogs] unmarshal login log content failed: %v", err.Error()) + continue + } + list = append(list, types.UserLoginLog{ + Id: datum.Id, + UserId: datum.ObjectID, + LoginIP: content.LoginIP, + UserAgent: content.UserAgent, + Success: content.Success, + Timestamp: datum.CreatedAt.UnixMilli(), + }) + } + return &types.GetUserLoginLogsResponse{ Total: total, List: list, diff --git a/internal/logic/admin/user/getUserSubscribeLogsLogic.go b/internal/logic/admin/user/getUserSubscribeLogsLogic.go index aa64873..ca33355 100644 --- a/internal/logic/admin/user/getUserSubscribeLogsLogic.go +++ b/internal/logic/admin/user/getUserSubscribeLogsLogic.go @@ -3,7 +3,7 @@ package user import ( "context" - "github.com/perfect-panel/server/internal/model/user" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" @@ -28,10 +28,7 @@ func NewGetUserSubscribeLogsLogic(ctx context.Context, svcCtx *svc.ServiceContex } func (l *GetUserSubscribeLogsLogic) GetUserSubscribeLogs(req *types.GetUserSubscribeLogsRequest) (resp *types.GetUserSubscribeLogsResponse, err error) { - data, total, err := l.svcCtx.UserModel.FilterSubscribeLogList(l.ctx, req.Page, req.Size, &user.SubscribeLogFilterParams{ - UserSubscribeId: req.SubscribeId, - UserId: req.UserId, - }) + data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{}) if err != nil { l.Errorw("[GetUserSubscribeLogs] Get User Subscribe Logs Error:", logger.Field("err", err.Error())) diff --git a/internal/logic/admin/user/getUserSubscribeResetTrafficLogsLogic.go b/internal/logic/admin/user/getUserSubscribeResetTrafficLogsLogic.go new file mode 100644 index 0000000..fb01d01 --- /dev/null +++ b/internal/logic/admin/user/getUserSubscribeResetTrafficLogsLogic.go @@ -0,0 +1,62 @@ +package user + +import ( + "context" + + "github.com/perfect-panel/server/internal/model/log" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" +) + +type GetUserSubscribeResetTrafficLogsLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// Get user subcribe reset traffic logs +func NewGetUserSubscribeResetTrafficLogsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserSubscribeResetTrafficLogsLogic { + return &GetUserSubscribeResetTrafficLogsLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *GetUserSubscribeResetTrafficLogsLogic) GetUserSubscribeResetTrafficLogs(req *types.GetUserSubscribeResetTrafficLogsRequest) (resp *types.GetUserSubscribeResetTrafficLogsResponse, err error) { + data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: req.Page, + Size: req.Size, + Type: log.TypeResetSubscribe.Uint8(), + ObjectID: req.UserSubscribeId, + }) + if err != nil { + l.Errorf("[ResetSubscribeTrafficLog] failed to filter system log: %v", err) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "FilterSystemLog failed, err: %v", err) + } + + var list []types.ResetSubscribeTrafficLog + + for _, item := range data { + var content log.ResetSubscribe + if err = content.Unmarshal([]byte(item.Content)); err != nil { + l.Errorf("[ResetSubscribeTrafficLog] failed to unmarshal log: %v", err) + continue + } + list = append(list, types.ResetSubscribeTrafficLog{ + Id: item.Id, + Type: content.Type, + OrderNo: content.OrderNo, + Timestamp: content.Timestamp, + UserSubscribeId: item.ObjectID, + }) + } + + return &types.GetUserSubscribeResetTrafficLogsResponse{ + Total: total, + List: list, + }, nil +} diff --git a/internal/logic/admin/user/updateUserBasicInfoLogic.go b/internal/logic/admin/user/updateUserBasicInfoLogic.go index c177fd9..9f57f75 100644 --- a/internal/logic/admin/user/updateUserBasicInfoLogic.go +++ b/internal/logic/admin/user/updateUserBasicInfoLogic.go @@ -4,7 +4,9 @@ import ( "context" "os" "strings" + "time" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" @@ -37,13 +39,90 @@ func (l *UpdateUserBasicInfoLogic) UpdateUserBasicInfo(req *types.UpdateUserBasi isDemo := strings.ToLower(os.Getenv("PPANEL_MODE")) == "demo" - tool.DeepCopy(userInfo, req) if req.Avatar != "" && !tool.IsValidImageSize(req.Avatar, 1024) { return errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "Invalid Image Size") } - userInfo.Balance = req.Balance - userInfo.GiftAmount = req.GiftAmount - userInfo.Commission = req.Commission + + if userInfo.Balance != req.Balance { + change := req.Balance - userInfo.Balance + balanceLog := log.Balance{ + Type: log.BalanceTypeAdjust, + Amount: change, + OrderNo: "", + Balance: req.Balance, + Timestamp: time.Now().UnixMilli(), + } + content, _ := balanceLog.Marshal() + + err = l.svcCtx.LogModel.Insert(l.ctx, &log.SystemLog{ + Type: log.TypeBalance.Uint8(), + Date: time.Now().Format(time.DateOnly), + ObjectID: userInfo.Id, + Content: string(content), + }) + if err != nil { + l.Errorw("[UpdateUserBasicInfoLogic] Insert Balance Log Error:", logger.Field("err", err.Error()), logger.Field("userId", req.UserId)) + return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "Insert Balance Log Error") + } + userInfo.Balance = req.Balance + } + + if userInfo.GiftAmount != req.GiftAmount { + change := req.GiftAmount - userInfo.GiftAmount + if change != 0 { + var changeType uint16 + if userInfo.GiftAmount < req.GiftAmount { + changeType = log.GiftTypeIncrease + } else { + changeType = log.GiftTypeReduce + } + giftLog := log.Gift{ + Type: changeType, + Amount: change, + Balance: req.GiftAmount, + Remark: "Admin adjustment", + Timestamp: time.Now().UnixMilli(), + } + content, _ := giftLog.Marshal() + // Add gift amount change log + err = l.svcCtx.LogModel.Insert(l.ctx, &log.SystemLog{ + Type: log.TypeGift.Uint8(), + Date: time.Now().Format(time.DateOnly), + ObjectID: userInfo.Id, + Content: string(content), + }) + if err != nil { + l.Errorw("[UpdateUserBasicInfoLogic] Insert Balance Log Error:", logger.Field("err", err.Error()), logger.Field("userId", req.UserId)) + return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "Insert Balance Log Error") + } + userInfo.GiftAmount = req.GiftAmount + } + } + + if req.Commission != userInfo.Commission { + + commentLog := log.Commission{ + Type: log.CommissionTypeAdjust, + Amount: req.Commission - userInfo.Commission, + Timestamp: time.Now().UnixMilli(), + } + + content, _ := commentLog.Marshal() + err = l.svcCtx.LogModel.Insert(l.ctx, &log.SystemLog{ + Type: log.TypeCommission.Uint8(), + Date: time.Now().Format(time.DateOnly), + ObjectID: userInfo.Id, + Content: string(content), + }) + if err != nil { + l.Errorw("[UpdateUserBasicInfoLogic] Insert Commission Log Error:", logger.Field("err", err.Error()), logger.Field("userId", req.UserId)) + return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "Insert Commission Log Error") + } + userInfo.Commission = req.Commission + } + tool.DeepCopy(userInfo, req) + userInfo.OnlyFirstPurchase = &req.OnlyFirstPurchase + userInfo.ReferralPercentage = req.ReferralPercentage if req.Password != "" { if userInfo.Id == 2 && isDemo { diff --git a/internal/logic/app/announcement/queryAnnouncementLogic.go b/internal/logic/app/announcement/queryAnnouncementLogic.go deleted file mode 100644 index 72be867..0000000 --- a/internal/logic/app/announcement/queryAnnouncementLogic.go +++ /dev/null @@ -1,47 +0,0 @@ -package announcement - -import ( - "context" - - "github.com/perfect-panel/server/internal/model/announcement" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" -) - -type QueryAnnouncementLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// NewQueryAnnouncementLogic Query announcement -func NewQueryAnnouncementLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryAnnouncementLogic { - return &QueryAnnouncementLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *QueryAnnouncementLogic) QueryAnnouncement(req *types.QueryAnnouncementRequest) (resp *types.QueryAnnouncementResponse, err error) { - enable := true - total, list, err := l.svcCtx.AnnouncementModel.GetAnnouncementListByPage(l.ctx, req.Page, req.Size, announcement.Filter{ - Show: &enable, - Pinned: req.Pinned, - Popup: req.Popup, - }) - if err != nil { - l.Error("[QueryAnnouncementLogic] GetAnnouncementListByPage error", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "GetAnnouncementListByPage error: %v", err.Error()) - } - resp = &types.QueryAnnouncementResponse{} - resp.Total = total - resp.List = make([]types.Announcement, 0) - tool.DeepCopy(&resp.List, list) - return -} diff --git a/internal/logic/app/auth/checkLogic.go b/internal/logic/app/auth/checkLogic.go deleted file mode 100644 index 8114b96..0000000 --- a/internal/logic/app/auth/checkLogic.go +++ /dev/null @@ -1,41 +0,0 @@ -package auth - -import ( - "context" - - "github.com/pkg/errors" - "gorm.io/gorm" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" -) - -type CheckLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Check Account -func NewCheckLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CheckLogic { - return &CheckLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *CheckLogic) Check(req *types.AppAuthCheckRequest) (resp *types.AppAuthCheckResponse, err error) { - resp = &types.AppAuthCheckResponse{} - _, err = findUserByMethod(l.ctx, l.svcCtx, req.Method, req.Identifier, req.Account, req.AreaCode) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - resp.Status = false - return resp, nil - } - return resp, err - } - resp.Status = true - return -} diff --git a/internal/logic/app/auth/findUserByMethod.go b/internal/logic/app/auth/findUserByMethod.go deleted file mode 100644 index edc3dcb..0000000 --- a/internal/logic/app/auth/findUserByMethod.go +++ /dev/null @@ -1,59 +0,0 @@ -package auth - -import ( - "context" - - "github.com/perfect-panel/server/pkg/authmethod" - - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/phone" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - "gorm.io/gorm" -) - -func findUserByMethod(ctx context.Context, svcCtx *svc.ServiceContext, method, identifier, account, areaCode string) (userInfo *user.User, err error) { - var authMethods *user.AuthMethods - switch method { - case authmethod.Email: - authMethods, err = svcCtx.UserModel.FindUserAuthMethodByOpenID(ctx, authmethod.Email, account) - case authmethod.Mobile: - phoneNumber, err := phone.FormatToE164(areaCode, account) - if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.TelephoneError), "Invalid phone number") - } - authMethods, err = svcCtx.UserModel.FindUserAuthMethodByOpenID(ctx, authmethod.Mobile, phoneNumber) - if err != nil { - return nil, err - } - case authmethod.Device: - userDevice, err := svcCtx.UserModel.FindOneDeviceByIdentifier(ctx, identifier) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, err - } - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query user device imei error") - } - return svcCtx.UserModel.FindOne(ctx, userDevice.UserId) - default: - return nil, errors.Wrapf(xerr.NewErrCode(xerr.UserNotExist), "unknown method") - } - if err != nil { - return nil, err - } - return svcCtx.UserModel.FindOne(ctx, authMethods.UserId) -} - -func existError(method string) error { - switch method { - case authmethod.Email: - return errors.Wrapf(xerr.NewErrCode(xerr.EmailExist), "") - case authmethod.Mobile: - return errors.Wrapf(xerr.NewErrCode(xerr.TelephoneExist), "") - case authmethod.Device: - return errors.Wrapf(xerr.NewErrCode(xerr.DeviceExist), "") - default: - return errors.New("unknown method") - } -} diff --git a/internal/logic/app/auth/getAppConfigLogic.go b/internal/logic/app/auth/getAppConfigLogic.go deleted file mode 100644 index 26ce7f2..0000000 --- a/internal/logic/app/auth/getAppConfigLogic.go +++ /dev/null @@ -1,119 +0,0 @@ -package auth - -import ( - "context" - "encoding/json" - "fmt" - "strings" - - "github.com/perfect-panel/server/internal/model/application" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - "gorm.io/gorm" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" -) - -type GetAppConfigLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// GetAppConfig -func NewGetAppConfigLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetAppConfigLogic { - return &GetAppConfigLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *GetAppConfigLogic) GetAppConfig(req *types.AppConfigRequest) (resp *types.AppConfigResponse, err error) { - resp = &types.AppConfigResponse{} - systems, err := l.svcCtx.SystemModel.GetSiteConfig(l.ctx) - if err != nil { - l.Errorw("[QueryApplicationConfig] GetSiteConfig error: ", logger.Field("error", err.Error())) - } - for _, sysVal := range systems { - if sysVal.Key == "CustomData" { - jsonStr := strings.ReplaceAll(sysVal.Value, "\\", "") - customData := make(map[string]interface{}) - if err = json.Unmarshal([]byte(jsonStr), &customData); err != nil { - break - } - - website := customData["website"] - if website != nil { - resp.OfficialWebsite = fmt.Sprintf("%v", website) - } - - contacts := customData["contacts"] - if contacts != nil { - contactsJson, err := json.Marshal(contacts) - if err == nil { - contactsMap := make(map[string]string) - err = json.Unmarshal(contactsJson, &contactsMap) - if err == nil { - resp.OfficialEmail = fmt.Sprintf("%v", contactsMap["email"]) - resp.OfficialTelegram = fmt.Sprintf("%v", contactsMap["telegram"]) - resp.OfficialTelephone = fmt.Sprintf("%v", contactsMap["telephone"]) - } - } - } - break - } - } - - var applications []*application.Application - err = l.svcCtx.ApplicationModel.Transaction(l.ctx, func(tx *gorm.DB) (err error) { - return tx.Model(applications).Preload("ApplicationVersions").Find(&applications).Error - }) - if err != nil { - l.Errorw("[QueryApplicationConfig] get application error: ", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "get application error: %v", err.Error()) - } - - if len(applications) == 0 { - return resp, nil - } - - isOk := false - for _, app := range applications { - if isOk { - break - } - resp.Application.Name = app.Name - resp.Application.Description = app.Description - applicationVersions := app.ApplicationVersions - if len(applicationVersions) != 0 { - for _, applicationVersion := range applicationVersions { - if applicationVersion.Platform == req.UserAgent { - resp.Application.Id = applicationVersion.ApplicationId - resp.Application.Url = applicationVersion.Url - resp.Application.Version = applicationVersion.Version - resp.Application.VersionDescription = applicationVersion.Description - resp.Application.IsDefault = applicationVersion.IsDefault - isOk = true - break - } - } - } - } - - configs, err := l.svcCtx.ApplicationModel.FindOneConfig(l.ctx, 1) - if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - l.Logger.Error("[GetAppInfo] FindOneAppConfig error: ", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "GetAppInfo FindOneAppConfig error: %v", err.Error()) - } - resp.EncryptionKey = configs.EncryptionKey - resp.EncryptionMethod = configs.EncryptionMethod - resp.Domains = strings.Split(configs.Domains, ";") - resp.StartupPicture = configs.StartupPicture - resp.StartupPictureSkipTime = configs.StartupPictureSkipTime - resp.InvitationLink = configs.InvitationLink - resp.KrWebsiteId = configs.KrWebsiteId - return -} diff --git a/internal/logic/app/auth/loginLogic.go b/internal/logic/app/auth/loginLogic.go deleted file mode 100644 index 14b0751..0000000 --- a/internal/logic/app/auth/loginLogic.go +++ /dev/null @@ -1,194 +0,0 @@ -package auth - -import ( - "encoding/json" - "fmt" - "time" - - "github.com/perfect-panel/server/pkg/authmethod" - - "github.com/gin-gonic/gin" - - "github.com/perfect-panel/server/pkg/constant" - "github.com/perfect-panel/server/pkg/phone" - - "github.com/perfect-panel/server/internal/config" - "github.com/perfect-panel/server/internal/logic/common" - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/jwt" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/uuidx" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - "gorm.io/gorm" -) - -type LoginLogic struct { - logger.Logger - ctx *gin.Context - svcCtx *svc.ServiceContext -} - -// Login -func NewLoginLogic(ctx *gin.Context, svcCtx *svc.ServiceContext) *LoginLogic { - return &LoginLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *LoginLogic) Login(req *types.AppAuthRequest) (resp *types.AppAuthRespone, err error) { - - loginStatus := false - var userInfo *user.User - // Record login status - defer func(svcCtx *svc.ServiceContext) { - if userInfo != nil && userInfo.Id != 0 { - if err := svcCtx.UserModel.InsertLoginLog(l.ctx, &user.LoginLog{ - UserId: userInfo.Id, - LoginIP: l.ctx.ClientIP(), - UserAgent: l.ctx.Request.UserAgent(), - Success: &loginStatus, - }); err != nil { - l.Errorw("InsertLoginLog Error", logger.Field("error", err.Error())) - } - } - }(l.svcCtx) - - resp = &types.AppAuthRespone{} - //query user - userInfo, err = findUserByMethod(l.ctx, l.svcCtx, req.Method, req.Identifier, req.Account, req.AreaCode) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.UserPasswordError), "user password") - } - return resp, err - } - - switch req.Method { - case authmethod.Email: - - if !l.svcCtx.Config.Email.Enable { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.EmailNotEnabled), "Email function is not enabled yet") - } - - if req.Code != "" { - cacheKey := fmt.Sprintf("%s:%s:%s", config.AuthCodeCacheKey, constant.Security.String(), req.Account) - value, err := l.svcCtx.Redis.Get(l.ctx, cacheKey).Result() - if err != nil { - l.Errorw("Redis Error", logger.Field("error", err.Error()), logger.Field("cacheKey", cacheKey)) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error") - } - - var payload common.CacheKeyPayload - err = json.Unmarshal([]byte(value), &payload) - if err != nil { - l.Errorw("Unmarshal Error", logger.Field("error", err.Error()), logger.Field("value", value)) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error") - } - - if payload.Code != req.Code { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error") - } - l.svcCtx.Redis.Del(l.ctx, cacheKey) - } else { - // Verify password - if !tool.VerifyPassWord(req.Password, userInfo.Password) { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.UserPasswordError), "user password") - } - } - case authmethod.Mobile: - if !l.svcCtx.Config.Mobile.Enable { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SmsNotEnabled), "sms login is not enabled") - } - phoneNumber, err := phone.FormatToE164(req.AreaCode, req.Account) - if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.TelephoneError), "Invalid phone number") - } - - if req.Code != "" { - cacheKey := fmt.Sprintf("%s:%s:%s", config.AuthCodeTelephoneCacheKey, constant.Security, phoneNumber) - value, err := l.svcCtx.Redis.Get(l.ctx, cacheKey).Result() - if err != nil { - l.Errorw("Redis Error", logger.Field("error", err.Error()), logger.Field("cacheKey", cacheKey)) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error") - } - - if value == "" { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error") - } - - var payload common.CacheKeyPayload - if err := json.Unmarshal([]byte(value), &payload); err != nil { - l.Errorw("[SendSmsCode]: Unmarshal Error", logger.Field("error", err.Error()), logger.Field("value", value)) - } - if payload.Code != req.Code { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error") - } - l.svcCtx.Redis.Del(l.ctx, cacheKey) - } else { - // Verify password - if !tool.VerifyPassWord(req.Password, userInfo.Password) { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.UserPasswordError), "user password") - } - } - case authmethod.Device: - default: - return nil, existError(req.Method) - } - - device, err := l.svcCtx.UserModel.FindOneDeviceByIdentifier(l.ctx, req.Identifier) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - if req.Method == authmethod.Device { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.UserNotExist), "device not exist") - } - //Add User Device - userInfo.UserDevices = append(userInfo.UserDevices, user.Device{ - UserAgent: req.UserAgent, - Identifier: req.Identifier, - Ip: l.ctx.ClientIP(), - }) - err = l.svcCtx.UserModel.Update(l.ctx, userInfo) - if err != nil { - l.Errorw("[UpdateUserBindDevice] Fail", logger.Field("error", err.Error())) - } - } - } else { - //Change the user who owns the device - if device.UserId != userInfo.Id { - device.UserId = userInfo.Id - } - device.Ip = l.ctx.ClientIP() - err = l.svcCtx.UserModel.UpdateDevice(l.ctx, device) - if err != nil { - l.Errorw("[UpdateUserBindDevice] Fail", logger.Field("error", err.Error())) - } - } - - // Generate session id - sessionId := uuidx.NewUUID().String() - // Generate token - token, err := jwt.NewJwtToken( - l.svcCtx.Config.JwtAuth.AccessSecret, - time.Now().Unix(), - l.svcCtx.Config.JwtAuth.AccessExpire, - jwt.WithOption("UserId", userInfo.Id), - jwt.WithOption("SessionId", sessionId), - ) - if err != nil { - l.Logger.Error("[UserLogin] token generate error", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "token generate error: %v", err.Error()) - } - sessionIdCacheKey := fmt.Sprintf("%v:%v", config.SessionIdKey, sessionId) - if err = l.svcCtx.Redis.Set(l.ctx, sessionIdCacheKey, userInfo.Id, time.Duration(l.svcCtx.Config.JwtAuth.AccessExpire)*time.Second).Err(); err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "set session id error: %v", err.Error()) - } - - resp.Token = token - return -} diff --git a/internal/logic/app/auth/registerLogic.go b/internal/logic/app/auth/registerLogic.go deleted file mode 100644 index 5d43ed4..0000000 --- a/internal/logic/app/auth/registerLogic.go +++ /dev/null @@ -1,249 +0,0 @@ -package auth - -import ( - "encoding/json" - "fmt" - "time" - - "github.com/perfect-panel/server/pkg/authmethod" - - "github.com/gin-gonic/gin" - - "github.com/perfect-panel/server/internal/config" - "github.com/perfect-panel/server/internal/logic/common" - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/constant" - "github.com/perfect-panel/server/pkg/jwt" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/phone" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/uuidx" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - "gorm.io/gorm" -) - -type CacheKeyPayload struct { - Code string `json:"code"` - LastAt int64 `json:"lastAt"` -} -type RegisterLogic struct { - logger.Logger - ctx *gin.Context - svcCtx *svc.ServiceContext -} - -// Register -func NewRegisterLogic(ctx *gin.Context, svcCtx *svc.ServiceContext) *RegisterLogic { - return &RegisterLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *RegisterLogic) Register(req *types.AppAuthRequest) (resp *types.AppAuthRespone, err error) { - resp = &types.AppAuthRespone{} - var referer *user.User - c := l.svcCtx.Config.Register - // Check if the registration is stopped - if c.StopRegister { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.StopRegister), "stop register") - } - - if req.Invite == "" { - if l.svcCtx.Config.Invite.ForcedInvite { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.InviteCodeError), "invite code is required") - } - } else { - // Check if the invite code is valid - referer, err = l.svcCtx.UserModel.FindOneByReferCode(l.ctx, req.Invite) - if err != nil { - l.Errorw("FindOneByReferCode Error", logger.Field("error", err)) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.InviteCodeError), "invite code is invalid") - } - } - - if req.Password == "" { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.PasswordIsEmpty), "Password required") - } - - userInfo, err := findUserByMethod(l.ctx, l.svcCtx, req.Method, req.Identifier, req.Account, req.AreaCode) - if err == nil && userInfo != nil { - return nil, existError(req.Method) - } - if !errors.Is(err, gorm.ErrRecordNotFound) { - return nil, err - } - // Generate password - pwd := tool.EncodePassWord(req.Password) - userInfo = &user.User{ - Password: pwd, - } - if referer != nil { - userInfo.RefererId = referer.Id - } - switch req.Method { - case authmethod.Email: - if !l.svcCtx.Config.Email.Enable { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.EmailNotEnabled), "Email function is not enabled yet") - } - if l.svcCtx.Config.Email.EnableVerify { - cacheKey := fmt.Sprintf("%s:%s:%s", config.AuthCodeCacheKey, constant.Register.String(), req.Account) - value, err := l.svcCtx.Redis.Get(l.ctx, cacheKey).Result() - if err != nil { - l.Errorw("Redis Error", logger.Field("error", err.Error()), logger.Field("cacheKey", cacheKey)) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error") - } - - var payload common.CacheKeyPayload - err = json.Unmarshal([]byte(value), &payload) - if err != nil { - l.Errorw("Unmarshal Error", logger.Field("error", err.Error()), logger.Field("value", value)) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error") - } - - if payload.Code != req.Code { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error") - } - } - userInfo.AuthMethods = []user.AuthMethods{{ - AuthType: authmethod.Email, - AuthIdentifier: req.Account, - }} - - case authmethod.Mobile: - if req.AreaCode == "" { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.TelephoneAreaCodeIsEmpty), "area code required") - } - - if !l.svcCtx.Config.Mobile.Enable { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SmsNotEnabled), "sms login is not enabled") - } - phoneNumber, err := phone.FormatToE164(req.AreaCode, req.Account) - if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.TelephoneError), "Invalid phone number") - } - cacheKey := fmt.Sprintf("%s:%s:%s", config.AuthCodeTelephoneCacheKey, constant.Register, phoneNumber) - value, err := l.svcCtx.Redis.Get(l.ctx, cacheKey).Result() - if err != nil { - l.Errorw("Redis Error", logger.Field("error", err.Error()), logger.Field("cacheKey", cacheKey)) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error") - } - - var payload CacheKeyPayload - _ = json.Unmarshal([]byte(value), &payload) - if payload.Code != req.Code { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error") - } - userInfo.AuthMethods = []user.AuthMethods{{ - AuthType: authmethod.Mobile, - AuthIdentifier: phoneNumber, - Verified: true, - }} - case authmethod.Device: - oneDevice, err := l.svcCtx.UserModel.FindOneDeviceByIdentifier(l.ctx, req.Identifier) - if err == nil && oneDevice != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DeviceExist), "device exist") - } - default: - return nil, existError(req.Method) - } - - device, err := l.svcCtx.UserModel.FindOneDeviceByIdentifier(l.ctx, req.Identifier) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - //Add User Device - userInfo.UserDevices = append(userInfo.UserDevices, user.Device{ - Ip: l.ctx.ClientIP(), - Identifier: req.Identifier, - UserAgent: req.UserAgent, - }) - } else { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query user info failed: %v", err.Error()) - } - } else { - //Delete Other User Device - err = l.svcCtx.UserModel.DeleteDevice(l.ctx, device.Id) - if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "delete old user device failed: %v", err.Error()) - } else { - //User Add Device - userInfo.UserDevices = append(userInfo.UserDevices, user.Device{ - Ip: l.ctx.ClientIP(), - Identifier: req.Identifier, - UserAgent: req.UserAgent, - }) - } - } - - err = l.svcCtx.UserModel.Transaction(l.ctx, func(db *gorm.DB) error { - // Save user information - if err := db.Create(userInfo).Error; err != nil { - return err - } - // Generate ReferCode - userInfo.ReferCode = uuidx.UserInviteCode(userInfo.Id) - // Update ReferCode - if err := db.Model(&user.User{}).Where("id = ?", userInfo.Id).Update("refer_code", userInfo.ReferCode).Error; err != nil { - return err - } - if l.svcCtx.Config.Register.EnableTrial { - // Active trial - if err = l.activeTrial(userInfo.Id); err != nil { - return err - } - } - return nil - }) - if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "insert user info failed: %v", err.Error()) - } - - // Generate session id - sessionId := uuidx.NewUUID().String() - // Generate token - token, err := jwt.NewJwtToken( - l.svcCtx.Config.JwtAuth.AccessSecret, - time.Now().Unix(), - l.svcCtx.Config.JwtAuth.AccessExpire, - jwt.WithOption("UserId", userInfo.Id), - jwt.WithOption("SessionId", sessionId), - ) - if err != nil { - l.Logger.Error("[UserLogin] token generate error", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "token generate error: %v", err.Error()) - } - - sessionIdCacheKey := fmt.Sprintf("%v:%v", config.SessionIdKey, sessionId) - if err := l.svcCtx.Redis.Set(l.ctx, sessionIdCacheKey, userInfo.Id, time.Duration(l.svcCtx.Config.JwtAuth.AccessExpire)*time.Second).Err(); err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "set session id error: %v", err.Error()) - } - - resp.Token = token - return -} - -func (l *RegisterLogic) activeTrial(uid int64) error { - sub, err := l.svcCtx.SubscribeModel.FindOne(l.ctx, l.svcCtx.Config.Register.TrialSubscribe) - if err != nil { - return err - } - userSub := &user.Subscribe{ - Id: 0, - UserId: uid, - OrderId: 0, - SubscribeId: sub.Id, - StartTime: time.Now(), - ExpireTime: tool.AddTime(l.svcCtx.Config.Register.TrialTimeUnit, l.svcCtx.Config.Register.TrialTime, time.Now()), - Traffic: sub.Traffic, - Download: 0, - Upload: 0, - Token: uuidx.SubscribeToken(fmt.Sprintf("Trial-%v", uid)), - UUID: uuidx.NewUUID().String(), - Status: 1, - } - return l.svcCtx.UserModel.InsertSubscribe(l.ctx, userSub) -} diff --git a/internal/logic/app/auth/resetPasswordLogic.go b/internal/logic/app/auth/resetPasswordLogic.go deleted file mode 100644 index 1b3feee..0000000 --- a/internal/logic/app/auth/resetPasswordLogic.go +++ /dev/null @@ -1,161 +0,0 @@ -package auth - -import ( - "encoding/json" - "fmt" - "time" - - "github.com/perfect-panel/server/pkg/authmethod" - - "github.com/gin-gonic/gin" - - "github.com/perfect-panel/server/pkg/constant" - "github.com/perfect-panel/server/pkg/phone" - - "github.com/perfect-panel/server/internal/config" - "github.com/perfect-panel/server/internal/logic/common" - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/jwt" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/uuidx" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - "gorm.io/gorm" -) - -type ResetPasswordLogic struct { - logger.Logger - ctx *gin.Context - svcCtx *svc.ServiceContext -} - -// Reset Password -func NewResetPasswordLogic(ctx *gin.Context, svcCtx *svc.ServiceContext) *ResetPasswordLogic { - return &ResetPasswordLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *ResetPasswordLogic) ResetPassword(req *types.AppAuthRequest) (resp *types.AppAuthRespone, err error) { - resp = &types.AppAuthRespone{} - userInfo, err := findUserByMethod(l.ctx, l.svcCtx, req.Method, req.Identifier, req.Account, req.AreaCode) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.UserNotExist), "query user info failed") - } - l.Errorw("FindOneByEmail Error", logger.Field("error", err)) - return nil, err - } - - switch req.Method { - case authmethod.Mobile: - if !l.svcCtx.Config.Mobile.Enable { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SmsNotEnabled), "sms login is not enabled") - } - phoneNumber, err := phone.FormatToE164(req.AreaCode, req.Account) - if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.TelephoneError), "Invalid phone number") - } - cacheKey := fmt.Sprintf("%s:%s:%s", config.AuthCodeTelephoneCacheKey, constant.Security, phoneNumber) - value, err := l.svcCtx.Redis.Get(l.ctx, cacheKey).Result() - if err != nil { - l.Errorw("Redis Error", logger.Field("error", err.Error()), logger.Field("cacheKey", cacheKey)) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error") - } - - var payload common.CacheKeyPayload - err = json.Unmarshal([]byte(value), &payload) - if err != nil { - l.Errorw("Unmarshal Error", logger.Field("error", err.Error()), logger.Field("value", value)) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error") - } - - if payload.Code != req.Code { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error") - } - case authmethod.Email: - if !l.svcCtx.Config.Email.Enable { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.EmailNotEnabled), "Email function is not enabled yet") - } - - cacheKey := fmt.Sprintf("%s:%s:%s", config.AuthCodeCacheKey, constant.Security.String(), req.Account) - value, err := l.svcCtx.Redis.Get(l.ctx, cacheKey).Result() - if err != nil { - l.Errorw("Redis Error", logger.Field("error", err.Error()), logger.Field("cacheKey", cacheKey)) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error") - } - - var payload CacheKeyPayload - err = json.Unmarshal([]byte(value), &payload) - if err != nil { - l.Errorw("Unmarshal Error", logger.Field("error", err.Error()), logger.Field("value", value)) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error") - } - - if payload.Code != req.Code { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error") - } - default: - return nil, errors.New("unknown method") - } - - userInfo.Password = tool.EncodePassWord(req.Password) - err = l.svcCtx.UserModel.Update(l.ctx, userInfo) - if err != nil { - l.Errorw("UpdateUser Error", logger.Field("error", err)) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "update user info failed: %v", err.Error()) - } - - device, err := l.svcCtx.UserModel.FindOneDeviceByIdentifier(l.ctx, req.Identifier) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - //Add User Device - userInfo.UserDevices = append(userInfo.UserDevices, user.Device{ - Ip: l.ctx.ClientIP(), - Identifier: req.Identifier, - UserAgent: req.UserAgent, - }) - } else { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query user info failed: %v", err.Error()) - } - } else { - if device.UserId != userInfo.Id { - //Change the user who owns the device - if device.UserId != userInfo.Id { - device.UserId = userInfo.Id - } - device.Ip = l.ctx.ClientIP() - err = l.svcCtx.UserModel.UpdateDevice(l.ctx, device) - if err != nil { - l.Errorw("[UpdateUserBindDevice] Fail", logger.Field("error", err.Error())) - } - } - } - - // Generate session id - sessionId := uuidx.NewUUID().String() - // Generate token - token, err := jwt.NewJwtToken( - l.svcCtx.Config.JwtAuth.AccessSecret, - time.Now().Unix(), - l.svcCtx.Config.JwtAuth.AccessExpire, - jwt.WithOption("UserId", userInfo.Id), - jwt.WithOption("SessionId", sessionId), - ) - if err != nil { - l.Logger.Error("[UserLogin] token generate error", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "token generate error: %v", err.Error()) - } - - sessionIdCacheKey := fmt.Sprintf("%v:%v", config.SessionIdKey, sessionId) - if err := l.svcCtx.Redis.Set(l.ctx, sessionIdCacheKey, userInfo.Id, time.Duration(l.svcCtx.Config.JwtAuth.AccessExpire)*time.Second).Err(); err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "set session id error: %v", err.Error()) - } - resp.Token = token - return -} diff --git a/internal/logic/app/document/queryDocumentDetailLogic.go b/internal/logic/app/document/queryDocumentDetailLogic.go deleted file mode 100644 index 4e033fa..0000000 --- a/internal/logic/app/document/queryDocumentDetailLogic.go +++ /dev/null @@ -1,39 +0,0 @@ -package document - -import ( - "context" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type QueryDocumentDetailLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// NewQueryDocumentDetailLogic Get document detail -func NewQueryDocumentDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryDocumentDetailLogic { - return &QueryDocumentDetailLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *QueryDocumentDetailLogic) QueryDocumentDetail(req *types.QueryDocumentDetailRequest) (resp *types.Document, err error) { - // find document - data, err := l.svcCtx.DocumentModel.FindOne(l.ctx, req.Id) - if err != nil { - l.Error("[QueryDocumentDetailLogic] FindOne error", logger.Field("id", req.Id), logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "FindOne error: %s", err.Error()) - } - resp = &types.Document{} - tool.DeepCopy(resp, data) - return -} diff --git a/internal/logic/app/document/queryDocumentListLogic.go b/internal/logic/app/document/queryDocumentListLogic.go deleted file mode 100644 index f42b266..0000000 --- a/internal/logic/app/document/queryDocumentListLogic.go +++ /dev/null @@ -1,48 +0,0 @@ -package document - -import ( - "context" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type QueryDocumentListLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Get document list -func NewQueryDocumentListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryDocumentListLogic { - return &QueryDocumentListLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *QueryDocumentListLogic) QueryDocumentList() (resp *types.QueryDocumentListResponse, err error) { - total, data, err := l.svcCtx.DocumentModel.GetDocumentListByAll(l.ctx) - if err != nil { - l.Error("[QueryDocumentList] error", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "QueryDocumentList error: %v", err.Error()) - } - resp = &types.QueryDocumentListResponse{ - Total: total, - List: make([]types.Document, 0), - } - for _, item := range data { - resp.List = append(resp.List, types.Document{ - Id: item.Id, - Title: item.Title, - Tags: tool.StringMergeAndRemoveDuplicates(item.Tags), - UpdatedAt: item.UpdatedAt.UnixMilli(), - }) - } - return -} diff --git a/internal/logic/app/node/getNodeListLogic.go b/internal/logic/app/node/getNodeListLogic.go deleted file mode 100644 index df2420c..0000000 --- a/internal/logic/app/node/getNodeListLogic.go +++ /dev/null @@ -1,82 +0,0 @@ -package node - -import ( - "context" - "strconv" - "strings" - - "github.com/perfect-panel/server/pkg/constant" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" -) - -type GetNodeListLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Get Node list -func NewGetNodeListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetNodeListLogic { - return &GetNodeListLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *GetNodeListLogic) GetNodeList(req *types.AppUserSubscbribeNodeRequest) (resp *types.AppUserSubscbribeNodeResponse, err error) { - resp = &types.AppUserSubscbribeNodeResponse{List: make([]types.AppUserSubscbribeNode, 0)} - userInfo := l.ctx.Value(constant.CtxKeyUser).(*user.User) - userSubscribe, err := l.svcCtx.UserModel.FindOneUserSubscribe(l.ctx, req.Id) - if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find user subscribe: %v", err.Error()) - } - - if userInfo.Id != userSubscribe.UserId { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "find user subscribe: %v", err.Error()) - } - - //拿到所有订阅下的服务组id - var ids []int64 - for _, idStr := range strings.Split(userSubscribe.Subscribe.ServerGroup, ",") { - id, err := strconv.ParseInt(idStr, 10, 64) - if err != nil { - continue - } - ids = append(ids, id) - } - - //根据服务组id拿到所有节点 - servers, err := l.svcCtx.ServerModel.FindServerListByGroupIds(l.ctx, ids) - if err != nil { - return nil, err - } - for _, server := range servers { - resp.List = append(resp.List, types.AppUserSubscbribeNode{ - Id: server.Id, - Uuid: userSubscribe.UUID, - Traffic: userSubscribe.Traffic, - Upload: userSubscribe.Upload, - Download: userSubscribe.Download, - RelayNode: server.RelayNode, - RelayMode: server.RelayMode, - Longitude: server.Longitude, - Latitude: server.Latitude, - Tags: strings.Split(server.Tags, ","), - Config: server.Config, - ServerAddr: server.ServerAddr, - Protocol: server.Protocol, - SpeedLimit: server.SpeedLimit, - City: server.City, - Country: server.Country, - Name: server.Name, - }) - } - return -} diff --git a/internal/logic/app/node/getRuleGroupListLogic.go b/internal/logic/app/node/getRuleGroupListLogic.go deleted file mode 100644 index 64f1645..0000000 --- a/internal/logic/app/node/getRuleGroupListLogic.go +++ /dev/null @@ -1,41 +0,0 @@ -package node - -import ( - "context" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type GetRuleGroupListLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Get rule group list -func NewGetRuleGroupListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetRuleGroupListLogic { - return &GetRuleGroupListLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *GetRuleGroupListLogic) GetRuleGroupList() (resp *types.AppRuleGroupListResponse, err error) { - nodeRuleGroupList, err := l.svcCtx.ServerModel.QueryAllRuleGroup(l.ctx) - if err != nil { - l.Logger.Error("[GetRuleGroupList] get subscribe rule group list failed: ", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "get subscribe rule group list failed: %v", err.Error()) - } - nodeRuleGroups := make([]types.ServerRuleGroup, 0) - tool.DeepCopy(&nodeRuleGroups, nodeRuleGroupList) - return &types.AppRuleGroupListResponse{ - Total: int64(len(nodeRuleGroups)), - List: nodeRuleGroups, - }, nil -} diff --git a/internal/logic/app/order/calculateCoupon.go b/internal/logic/app/order/calculateCoupon.go deleted file mode 100644 index 05f92c8..0000000 --- a/internal/logic/app/order/calculateCoupon.go +++ /dev/null @@ -1,13 +0,0 @@ -package order - -import ( - "github.com/perfect-panel/server/internal/model/coupon" -) - -func calculateCoupon(amount int64, couponInfo *coupon.Coupon) int64 { - if couponInfo.Type == 1 { - return int64(float64(amount) * (float64(couponInfo.Discount) / float64(100))) - } else { - return min(couponInfo.Discount, amount) - } -} diff --git a/internal/logic/app/order/calculateFee.go b/internal/logic/app/order/calculateFee.go deleted file mode 100644 index 9c0b2b9..0000000 --- a/internal/logic/app/order/calculateFee.go +++ /dev/null @@ -1,20 +0,0 @@ -package order - -import "github.com/perfect-panel/server/internal/model/payment" - -func calculateFee(amount int64, config *payment.Payment) int64 { - var fee float64 - switch config.FeeMode { - case 0: - return 0 - case 1: - fee = float64(amount) * (float64(config.FeePercent) / float64(100)) - case 2: - if amount > 0 { - fee = float64(config.FeeAmount) - } - case 3: - fee = float64(amount)*(float64(config.FeePercent)/float64(100)) + float64(config.FeeAmount) - } - return int64(fee) -} diff --git a/internal/logic/app/order/checkoutOrderLogic.go b/internal/logic/app/order/checkoutOrderLogic.go deleted file mode 100644 index 79fb745..0000000 --- a/internal/logic/app/order/checkoutOrderLogic.go +++ /dev/null @@ -1,325 +0,0 @@ -package order - -import ( - "context" - "encoding/json" - "fmt" - "strconv" - - paymentPlatform "github.com/perfect-panel/server/pkg/payment" - - "github.com/perfect-panel/server/pkg/constant" - - "github.com/hibiken/asynq" - "github.com/perfect-panel/server/internal/model/order" - "github.com/perfect-panel/server/internal/model/payment" - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/exchangeRate" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/payment/alipay" - "github.com/perfect-panel/server/pkg/payment/epay" - "github.com/perfect-panel/server/pkg/payment/stripe" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/xerr" - queueType "github.com/perfect-panel/server/queue/types" - "github.com/pkg/errors" - "gorm.io/gorm" -) - -type CheckoutOrderLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -type CurrencyConfig struct { - CurrencyUnit string - CurrencySymbol string - AccessKey string -} - -const ( - Stripe = "Stripe" - QR = "qr" - Link = "link" -) - -// NewCheckoutOrderLogic Checkout order -func NewCheckoutOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CheckoutOrderLogic { - return &CheckoutOrderLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *CheckoutOrderLogic) CheckoutOrder(req *types.CheckoutOrderRequest, requestHost string) (resp *types.CheckoutOrderResponse, err error) { - u, ok := l.ctx.Value(constant.CtxKeyUser).(*user.User) - if !ok { - l.Error("[CheckoutOrderLogic] Invalid access") - return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid access") - } - // find order - orderInfo, err := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, req.OrderNo) - if err != nil { - l.Error("[CheckoutOrderLogic] FindOneByOrderNo error", logger.Field("orderNo", req.OrderNo), logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "FindOneByOrderNo error: %s", err.Error()) - } - - if orderInfo.Status != 1 { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "Order status error") - } - - paymentConfig, err := l.svcCtx.PaymentModel.FindOne(l.ctx, orderInfo.PaymentId) - if err != nil { - l.Error("[CheckoutOrderLogic] FindOneByPaymentMark error", logger.Field("paymentMark", orderInfo.Method), logger.Field("PaymentID", orderInfo.PaymentId), logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "FindOneByPaymentMark error: %s", err.Error()) - } - var stripePayment *types.StripePayment = nil - var url, t string - - // switch payment method - switch paymentPlatform.ParsePlatform(paymentConfig.Platform) { - case paymentPlatform.Stripe: - result, err := l.stripePayment(paymentConfig.Config, orderInfo, u) - if err != nil { - l.Error("[CheckoutOrderLogic] stripePayment error", logger.Field("error", err.Error())) - return nil, err - } - stripePayment = result - t = Stripe - case paymentPlatform.EPay: - // epay - url, err = l.epayPayment(paymentConfig, orderInfo, req.ReturnUrl, requestHost) - if err != nil { - l.Error("[CheckoutOrderLogic] epayPayment error", logger.Field("error", err.Error())) - return nil, err - } - t = Link - case paymentPlatform.AlipayF2F: - // alipay f2f - url, err = l.alipayF2fPayment(paymentConfig, orderInfo, requestHost) - if err != nil { - return nil, err - } - t = QR - case paymentPlatform.Balance: - // balance - if err = l.balancePayment(u, orderInfo); err != nil { - return nil, err - } - t = paymentPlatform.Balance.String() - default: - return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "Payment method not supported") - } - return &types.CheckoutOrderResponse{ - Type: t, - CheckoutUrl: url, - Stripe: stripePayment, - }, nil -} - -// Query exchange rate -func (l *CheckoutOrderLogic) queryExchangeRate(to string, src int64) (amount float64, err error) { - amount = float64(src) / float64(100) - // query system currency - currency, err := l.svcCtx.SystemModel.GetCurrencyConfig(l.ctx) - if err != nil { - l.Error("[CheckoutOrderLogic] GetCurrencyConfig error", logger.Field("error", err.Error())) - return 0, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "GetCurrencyConfig error: %s", err.Error()) - } - configs := &CurrencyConfig{} - tool.SystemConfigSliceReflectToStruct(currency, configs) - if configs.AccessKey == "" { - return amount, nil - } - if configs.CurrencyUnit != to { - // query exchange rate - result, err := exchangeRate.GetExchangeRete(configs.CurrencyUnit, to, configs.AccessKey, 1) - if err != nil { - return 0, err - } - amount = result * amount - } - return amount, nil -} - -// Stripe Payment -func (l *CheckoutOrderLogic) stripePayment(config string, info *order.Order, u *user.User) (*types.StripePayment, error) { - // stripe WeChat pay or stripe alipay - stripeConfig := payment.StripeConfig{} - if err := json.Unmarshal([]byte(config), &stripeConfig); err != nil { - l.Error("[CheckoutOrderLogic] Unmarshal error", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "Unmarshal error: %s", err.Error()) - } - client := stripe.NewClient(stripe.Config{ - SecretKey: stripeConfig.SecretKey, - PublicKey: stripeConfig.PublicKey, - WebhookSecret: stripeConfig.WebhookSecret, - }) - // Calculate the amount with exchange rate - amount, err := l.queryExchangeRate("CNY", info.Amount) - if err != nil { - l.Error("[CheckoutOrderLogic] queryExchangeRate error", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "queryExchangeRate error: %s", err.Error()) - } - convertAmount := int64(amount * 100) - // create payment - result, err := client.CreatePaymentSheet(&stripe.Order{ - OrderNo: info.OrderNo, - Subscribe: strconv.FormatInt(info.SubscribeId, 10), - Amount: convertAmount, - Currency: "cny", - Payment: stripeConfig.Payment, - }, - &stripe.User{ - UserId: u.Id, - }) - if err != nil { - l.Error("[CheckoutOrderLogic] CreatePaymentSheet error", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "CreatePaymentSheet error: %s", err.Error()) - } - tradeNo := result.TradeNo - stripePayment := &types.StripePayment{ - PublishableKey: stripeConfig.PublicKey, - ClientSecret: result.ClientSecret, - Method: stripeConfig.Payment, - } - // save payment - info.TradeNo = tradeNo - err = l.svcCtx.OrderModel.Update(l.ctx, info) - if err != nil { - l.Error("[CheckoutOrderLogic] Update error", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Update error: %s", err.Error()) - } - return stripePayment, nil -} - -// epay payment -func (l *CheckoutOrderLogic) epayPayment(config *payment.Payment, info *order.Order, returnUrl, requestHost string) (string, error) { - epayConfig := payment.EPayConfig{} - if err := json.Unmarshal([]byte(config.Config), &epayConfig); err != nil { - l.Error("[CheckoutOrderLogic] Unmarshal error", logger.Field("error", err.Error())) - return "", errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "Unmarshal error: %s", err.Error()) - } - client := epay.NewClient(epayConfig.Pid, epayConfig.Url, epayConfig.Key) - // Calculate the amount with exchange rate - amount, err := l.queryExchangeRate("CNY", info.Amount) - if err != nil { - return "", err - } - var domain string - if config.Domain != "" { - domain = config.Domain - } else { - domain = fmt.Sprintf("http://%s", requestHost) - } - // create payment - url := client.CreatePayUrl(epay.Order{ - Name: l.svcCtx.Config.Site.SiteName, - Amount: amount, - OrderNo: info.OrderNo, - SignType: "MD5", - NotifyUrl: domain + "/v1/notify/epay", - ReturnUrl: returnUrl, - }) - return url, nil -} - -// alipay f2f payment -func (l *CheckoutOrderLogic) alipayF2fPayment(pay *payment.Payment, info *order.Order, requestHost string) (string, error) { - f2FConfig := payment.AlipayF2FConfig{} - if err := json.Unmarshal([]byte(pay.Config), &f2FConfig); err != nil { - l.Error("[CheckoutOrderLogic] Unmarshal error", logger.Field("error", err.Error())) - return "", errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "Unmarshal error: %s", err.Error()) - } - var domain string - if pay.Domain != "" { - domain = pay.Domain - } else { - domain = fmt.Sprintf("http://%s", requestHost) - } - client := alipay.NewClient(alipay.Config{ - AppId: f2FConfig.AppId, - PrivateKey: f2FConfig.PrivateKey, - PublicKey: f2FConfig.PublicKey, - InvoiceName: f2FConfig.InvoiceName, - NotifyURL: domain + "/notify/alipay", - }) - // Calculate the amount with exchange rate - amount, err := l.queryExchangeRate("CNY", info.Amount) - if err != nil { - l.Error("[CheckoutOrderLogic] queryExchangeRate error", logger.Field("error", err.Error())) - return "", errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "queryExchangeRate error: %s", err.Error()) - } - convertAmount := int64(amount * 100) - // create payment - QRCode, err := client.PreCreateTrade(l.ctx, alipay.Order{ - OrderNo: info.OrderNo, - Amount: convertAmount, - }) - if err != nil { - l.Error("[CheckoutOrderLogic] PreCreateTrade error", logger.Field("error", err.Error())) - return "", errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "PreCreateTrade error: %s", err.Error()) - } - return QRCode, nil -} - -// Balance payment -func (l *CheckoutOrderLogic) balancePayment(u *user.User, o *order.Order) error { - var userInfo user.User - err := l.svcCtx.UserModel.Transaction(l.ctx, func(db *gorm.DB) error { - err := db.Model(&user.User{}).Where("id = ?", u.Id).First(&userInfo).Error - if err != nil { - return err - } - - if userInfo.Balance < o.Amount { - return errors.Wrapf(xerr.NewErrCode(xerr.InsufficientBalance), "Insufficient balance") - } - // deduct balance - userInfo.Balance -= o.Amount - err = l.svcCtx.UserModel.Update(l.ctx, &userInfo) - if err != nil { - return err - } - // create balance log - balanceLog := &user.BalanceLog{ - Id: 0, - UserId: u.Id, - Amount: o.Amount, - Type: 3, - OrderId: o.Id, - Balance: userInfo.Balance, - } - err = db.Create(balanceLog).Error - if err != nil { - return err - } - return l.svcCtx.OrderModel.UpdateOrderStatus(l.ctx, o.OrderNo, 2) - }) - if err != nil { - l.Error("[CheckoutOrderLogic] Transaction error", logger.Field("error", err.Error()), logger.Field("orderNo", o.OrderNo)) - return err - } - // create activity order task - payload := queueType.ForthwithActivateOrderPayload{ - OrderNo: o.OrderNo, - } - bytes, err := json.Marshal(payload) - if err != nil { - l.Error("[CheckoutOrderLogic] Marshal error", logger.Field("error", err.Error())) - return err - } - - task := asynq.NewTask(queueType.ForthwithActivateOrder, bytes) - _, err = l.svcCtx.Queue.EnqueueContext(l.ctx, task) - if err != nil { - l.Error("[CheckoutOrderLogic] Enqueue error", logger.Field("error", err.Error())) - return err - } - l.Logger.Info("[CheckoutOrderLogic] Enqueue success", logger.Field("orderNo", o.OrderNo)) - return nil -} diff --git a/internal/logic/app/order/closeOrderLogic.go b/internal/logic/app/order/closeOrderLogic.go deleted file mode 100644 index 2bd1d44..0000000 --- a/internal/logic/app/order/closeOrderLogic.go +++ /dev/null @@ -1,186 +0,0 @@ -package order - -import ( - "context" - "encoding/json" - - paymentPlatform "github.com/perfect-panel/server/pkg/payment" - - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/pkg/payment/stripe" - "gorm.io/gorm" - - "github.com/perfect-panel/server/internal/model/order" - "github.com/perfect-panel/server/internal/model/payment" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/payment/alipay" -) - -type CloseOrderLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// NewCloseOrderLogic Close order -func NewCloseOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CloseOrderLogic { - return &CloseOrderLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *CloseOrderLogic) CloseOrder(req *types.CloseOrderRequest) error { - // Find order information by order number - orderInfo, err := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, req.OrderNo) - if err != nil { - l.Error("[CloseOrder] Find order info failed", - logger.Field("error", err.Error()), - logger.Field("orderNo", req.OrderNo), - ) - return nil - } - // If the order status is not 1, it means that the order has been closed or paid - if orderInfo.Status != 1 { - l.Info("[CloseOrder] Order status is not 1", - logger.Field("orderNo", req.OrderNo), - logger.Field("status", orderInfo.Status), - ) - return nil - } - if l.confirmationPayment(orderInfo) { - l.Info("[CloseOrder] Order has been paid", - logger.Field("orderNo", req.OrderNo), - logger.Field("status", orderInfo.Status), - ) - return nil - } - err = l.svcCtx.DB.Transaction(func(tx *gorm.DB) error { - // update order status - err := tx.Model(&order.Order{}).Where("order_no = ?", req.OrderNo).Update("status", 3).Error - if err != nil { - l.Error("[CloseOrder] Update order status failed", - logger.Field("error", err.Error()), - logger.Field("orderNo", req.OrderNo), - ) - return err - } - // refund deduction amount to user deduction balance - if orderInfo.GiftAmount > 0 { - userInfo, err := l.svcCtx.UserModel.FindOne(l.ctx, orderInfo.UserId) - if err != nil { - l.Error("[CloseOrder] Find user info failed", - logger.Field("error", err.Error()), - logger.Field("user_id", orderInfo.UserId), - ) - return err - } - deduction := userInfo.GiftAmount + orderInfo.GiftAmount - err = tx.Model(&user.User{}).Where("id = ?", orderInfo.UserId).Update("deduction", deduction).Error - if err != nil { - l.Error("[CloseOrder] Refund deduction amount failed", - logger.Field("error", err.Error()), - logger.Field("uid", orderInfo.UserId), - logger.Field("deduction", orderInfo.GiftAmount), - ) - return err - } - // Record the deduction refund log - giftAmountLog := &user.GiftAmountLog{ - UserId: orderInfo.UserId, - OrderNo: orderInfo.OrderNo, - Amount: orderInfo.GiftAmount, - Type: 1, - Balance: deduction, - Remark: "Order cancellation refund", - } - err = tx.Model(&user.GiftAmountLog{}).Create(giftAmountLog).Error - if err != nil { - l.Error("[CloseOrder] Record cancellation refund log failed", - logger.Field("error", err.Error()), - logger.Field("uid", orderInfo.UserId), - logger.Field("deduction", orderInfo.GiftAmount), - ) - return err - } - // update user cache - return l.svcCtx.UserModel.UpdateUserCache(l.ctx, userInfo) - } - return nil - }) - if err != nil { - return err - } - return nil -} - -// confirmationPayment Determine whether the payment is successful -// -//nolint:unused -func (l *CloseOrderLogic) confirmationPayment(order *order.Order) bool { - paymentConfig, err := l.svcCtx.PaymentModel.FindOne(l.ctx, order.PaymentId) - if err != nil { - l.Error("[CloseOrder] Find payment config failed", logger.Field("error", err.Error()), logger.Field("paymentMark", order.Method)) - return false - } - switch paymentPlatform.ParsePlatform(order.Method) { - case paymentPlatform.AlipayF2F: - if l.queryAlipay(paymentConfig, order.TradeNo) { - return true - } - case paymentPlatform.Stripe: - if l.queryStripe(paymentConfig, order.TradeNo) { - return true - } - default: - l.Info("[CloseOrder] Unsupported payment method", logger.Field("paymentMethod", order.Method)) - } - return false -} - -// queryAlipay Query Alipay payment status -func (l *CloseOrderLogic) queryAlipay(paymentConfig *payment.Payment, TradeNo string) bool { - config := payment.AlipayF2FConfig{} - if err := json.Unmarshal([]byte(paymentConfig.Config), &config); err != nil { - l.Error("[CloseOrder] Unmarshal payment config failed", logger.Field("error", err.Error()), logger.Field("config", paymentConfig.Config)) - return false - } - client := alipay.NewClient(alipay.Config{ - AppId: config.AppId, - PrivateKey: config.PrivateKey, - PublicKey: config.PublicKey, - InvoiceName: config.InvoiceName, - }) - status, err := client.QueryTrade(l.ctx, TradeNo) - if err != nil { - l.Error("[CloseOrder] Query trade failed", logger.Field("error", err.Error()), logger.Field("TradeNo", TradeNo)) - return false - } - if status == alipay.Success || status == alipay.Finished { - return true - } - return false -} - -// queryStripe Query Stripe payment status -func (l *CloseOrderLogic) queryStripe(paymentConfig *payment.Payment, TradeNo string) bool { - config := payment.StripeConfig{} - if err := json.Unmarshal([]byte(paymentConfig.Config), &config); err != nil { - l.Error("[CloseOrder] Unmarshal payment config failed", logger.Field("error", err.Error()), logger.Field("config", paymentConfig.Config)) - return false - } - client := stripe.NewClient(stripe.Config{ - PublicKey: config.PublicKey, - SecretKey: config.SecretKey, - WebhookSecret: config.WebhookSecret, - }) - status, err := client.QueryOrderStatus(TradeNo) - if err != nil { - l.Error("[CloseOrder] Query order status failed", logger.Field("error", err.Error()), logger.Field("TradeNo", TradeNo)) - return false - } - return status -} diff --git a/internal/logic/app/order/getDiscount.go b/internal/logic/app/order/getDiscount.go deleted file mode 100644 index c645e89..0000000 --- a/internal/logic/app/order/getDiscount.go +++ /dev/null @@ -1,14 +0,0 @@ -package order - -import "github.com/perfect-panel/server/internal/types" - -func getDiscount(discounts []types.SubscribeDiscount, inputMonths int64) float64 { - var finalDiscount int64 = 100 - - for _, discount := range discounts { - if inputMonths >= discount.Quantity && discount.Discount < finalDiscount { - finalDiscount = discount.Discount - } - } - return float64(finalDiscount) / float64(100) -} diff --git a/internal/logic/app/order/preCreateOrderLogic.go b/internal/logic/app/order/preCreateOrderLogic.go deleted file mode 100644 index 1f72559..0000000 --- a/internal/logic/app/order/preCreateOrderLogic.go +++ /dev/null @@ -1,123 +0,0 @@ -package order - -import ( - "context" - "encoding/json" - - "github.com/perfect-panel/server/internal/model/order" - "github.com/perfect-panel/server/pkg/tool" - - "github.com/perfect-panel/server/pkg/constant" - - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - "gorm.io/gorm" -) - -type PreCreateOrderLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Pre create order -func NewPreCreateOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PreCreateOrderLogic { - return &PreCreateOrderLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *PreCreateOrderLogic) PreCreateOrder(req *types.PurchaseOrderRequest) (resp *types.PreOrderResponse, err error) { - u, ok := l.ctx.Value(constant.CtxKeyUser).(*user.User) - if !ok { - logger.Error("current user is not found in context") - return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access") - } - // find subscribe plan - sub, err := l.svcCtx.SubscribeModel.FindOne(l.ctx, req.SubscribeId) - if err != nil { - l.Error("[PreCreateOrder] Database query error", logger.Field("error", err.Error()), logger.Field("subscribe_id", req.SubscribeId)) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find subscribe error: %v", err.Error()) - } - var discount float64 = 1 - if sub.Discount != "" { - var dis []types.SubscribeDiscount - _ = json.Unmarshal([]byte(sub.Discount), &dis) - discount = getDiscount(dis, req.Quantity) - } - price := sub.UnitPrice * req.Quantity - amount := int64(float64(price) * discount) - discountAmount := price - amount - var coupon int64 - if req.Coupon != "" { - couponInfo, err := l.svcCtx.CouponModel.FindOneByCode(l.ctx, req.Coupon) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.CouponNotExist), "coupon not found") - } - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find coupon error: %v", err.Error()) - } - if couponInfo.Count > 0 && couponInfo.Count <= couponInfo.UsedCount { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.CouponInsufficientUsage), "coupon used") - } - couponSub := tool.StringToInt64Slice(couponInfo.Subscribe) - if len(couponSub) > 0 && !tool.Contains(couponSub, req.SubscribeId) { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.CouponNotApplicable), "coupon not match") - } - var count int64 - err = l.svcCtx.DB.Transaction(func(tx *gorm.DB) error { - return tx.Model(&order.Order{}).Where("user_id = ? and coupon = ?", u.Id, req.Coupon).Count(&count).Error - }) - - if err != nil { - l.Errorw("[Purchase] Database query error", logger.Field("error", err.Error()), logger.Field("user_id", u.Id), logger.Field("coupon", req.Coupon)) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find coupon error: %v", err.Error()) - } - if couponInfo.UserLimit > 0 && count >= couponInfo.UserLimit { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.CouponInsufficientUsage), "coupon limit exceeded") - } - coupon = calculateCoupon(amount, couponInfo) - } - amount -= coupon - - var deductionAmount int64 - // Check user deduction amount - if u.GiftAmount > 0 { - if u.GiftAmount >= amount { - deductionAmount = amount - amount = 0 - } else { - deductionAmount = u.GiftAmount - amount -= u.GiftAmount - } - } - - payment, err := l.svcCtx.PaymentModel.FindOne(l.ctx, req.Payment) - if err != nil { - l.Logger.Error("[PreCreateOrder] Database query error", logger.Field("error", err.Error()), logger.Field("payment", req.Payment)) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find payment method error: %v", err.Error()) - } - var feeAmount int64 - // Calculate the handling fee - if amount > 0 { - feeAmount = calculateFee(amount, payment) - } - amount += feeAmount - - resp = &types.PreOrderResponse{ - Price: price, - Amount: amount, - Discount: discountAmount, - GiftAmount: deductionAmount, - Coupon: req.Coupon, - CouponDiscount: coupon, - FeeAmount: feeAmount, - } - return -} diff --git a/internal/logic/app/order/purchaseLogic.go b/internal/logic/app/order/purchaseLogic.go deleted file mode 100644 index 04a7992..0000000 --- a/internal/logic/app/order/purchaseLogic.go +++ /dev/null @@ -1,214 +0,0 @@ -package order - -import ( - "context" - "encoding/json" - "time" - - "github.com/perfect-panel/server/pkg/constant" - - "github.com/hibiken/asynq" - "github.com/perfect-panel/server/internal/model/order" - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/xerr" - queue "github.com/perfect-panel/server/queue/types" - "github.com/pkg/errors" - "gorm.io/gorm" -) - -type PurchaseLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -const CloseOrderTimeMinutes = 15 - -// purchase Subscription -func NewPurchaseLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PurchaseLogic { - return &PurchaseLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *PurchaseLogic) Purchase(req *types.PurchaseOrderRequest) (resp *types.PurchaseOrderResponse, err error) { - - u, ok := l.ctx.Value(constant.CtxKeyUser).(*user.User) - if !ok { - logger.Error("current user is not found in context") - return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access") - } - // find user subscription - - if l.svcCtx.Config.Subscribe.SingleModel { - userSub, err := l.svcCtx.UserModel.QueryUserSubscribe(l.ctx, u.Id) - if err != nil { - l.Error("[Purchase] Database query error", logger.Field("error", err.Error()), logger.Field("user_id", u.Id)) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find user subscription error: %v", err.Error()) - } - if len(userSub) > 0 { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.UserSubscribeExist), "user has subscription") - } - } - - // find subscribe plan - sub, err := l.svcCtx.SubscribeModel.FindOne(l.ctx, req.SubscribeId) - - if err != nil { - l.Error("[Purchase] Database query error", logger.Field("error", err.Error()), logger.Field("subscribe_id", req.SubscribeId)) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find subscribe error: %v", err.Error()) - } - // check subscribe plan status - if !*sub.Sell { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "subscribe not sell") - } - var discount float64 = 1 - if sub.Discount != "" { - var dis []types.SubscribeDiscount - _ = json.Unmarshal([]byte(sub.Discount), &dis) - discount = getDiscount(dis, req.Quantity) - } - price := sub.UnitPrice * req.Quantity - // discount amount - amount := int64(float64(price) * discount) - discountAmount := price - amount - var coupon int64 = 0 - // Calculate the coupon deduction - if req.Coupon != "" { - couponInfo, err := l.svcCtx.CouponModel.FindOneByCode(l.ctx, req.Coupon) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.CouponNotExist), "coupon not found") - } - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find coupon error: %v", err.Error()) - } - if couponInfo.Count <= couponInfo.UsedCount { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.CouponInsufficientUsage), "coupon used") - } - couponSub := tool.StringToInt64Slice(couponInfo.Subscribe) - if len(couponSub) > 0 && !tool.Contains(couponSub, req.SubscribeId) { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.CouponNotApplicable), "coupon not match") - } - var count int64 - err = l.svcCtx.DB.Transaction(func(tx *gorm.DB) error { - return tx.Model(&order.Order{}).Where("user_id = ? and coupon = ?", u.Id, req.Coupon).Count(&count).Error - }) - - if err != nil { - l.Errorw("[Purchase] Database query error", logger.Field("error", err.Error()), logger.Field("user_id", u.Id), logger.Field("coupon", req.Coupon)) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find coupon error: %v", err.Error()) - } - if count >= couponInfo.UserLimit { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.CouponInsufficientUsage), "coupon limit exceeded") - } - coupon = calculateCoupon(amount, couponInfo) - } - // Calculate the handling fee - amount -= coupon - var deductionAmount int64 - // Check user deduction amount - if u.GiftAmount > 0 { - if u.GiftAmount >= amount { - deductionAmount = amount - amount = 0 - u.GiftAmount -= amount - } else { - deductionAmount = u.GiftAmount - amount -= u.GiftAmount - u.GiftAmount = 0 - } - } - // find payment method - payment, err := l.svcCtx.PaymentModel.FindOne(l.ctx, req.Payment) - if err != nil { - l.Logger.Error("[Purchase] Database query error", logger.Field("error", err.Error()), logger.Field("payment", req.Payment)) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find payment method error: %v", err.Error()) - } - var feeAmount int64 - // Calculate the handling fee - if amount > 0 { - feeAmount = calculateFee(amount, payment) - } - // query user is new purchase or renewal - isNew, err := l.svcCtx.OrderModel.IsUserEligibleForNewOrder(l.ctx, u.Id) - if err != nil { - l.Error("[Purchase] Database query error", logger.Field("error", err.Error()), logger.Field("user_id", u.Id)) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find user order error: %v", err.Error()) - } - // create order - orderInfo := &order.Order{ - UserId: u.Id, - OrderNo: tool.GenerateTradeNo(), - Type: 1, - Quantity: req.Quantity, - Price: price, - Amount: amount, - Discount: discountAmount, - GiftAmount: deductionAmount, - Coupon: req.Coupon, - CouponDiscount: coupon, - PaymentId: req.Payment, - Method: payment.Platform, - FeeAmount: feeAmount, - Status: 1, - IsNew: isNew, - SubscribeId: req.SubscribeId, - } - // Database transaction - err = l.svcCtx.DB.Transaction(func(db *gorm.DB) error { - // update user deduction && Pre deduction ,Return after canceling the order - if orderInfo.GiftAmount > 0 { - // update user deduction && Pre deduction ,Return after canceling the order - if e := l.svcCtx.UserModel.Update(l.ctx, u, db); err != nil { - l.Error("[Purchase] Database update error", logger.Field("error", err.Error()), logger.Field("user", u)) - return e - } - // create deduction record - giftAmountLog := user.GiftAmountLog{ - UserId: orderInfo.UserId, - OrderNo: orderInfo.OrderNo, - Amount: orderInfo.GiftAmount, - Type: 2, - Balance: u.GiftAmount, - Remark: "Purchase order deduction", - } - if e := db.Model(&user.GiftAmountLog{}).Create(&giftAmountLog).Error; e != nil { - l.Error("[Purchase] Database insert error", - logger.Field("error", err.Error()), - logger.Field("deductionLog", giftAmountLog), - ) - return e - } - } - // insert order - return db.Model(&order.Order{}).Create(&orderInfo).Error - }) - if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "insert order error: %v", err.Error()) - } - // Deferred task - payload := queue.DeferCloseOrderPayload{ - OrderNo: orderInfo.OrderNo, - } - val, err := json.Marshal(payload) - if err != nil { - l.Error("[CreateOrder] Marshal payload error", logger.Field("error", err.Error()), logger.Field("payload", payload)) - } - task := asynq.NewTask(queue.DeferCloseOrder, val, asynq.MaxRetry(3)) - taskInfo, err := l.svcCtx.Queue.Enqueue(task, asynq.ProcessIn(CloseOrderTimeMinutes*time.Minute)) - if err != nil { - l.Error("[CreateOrder] Enqueue task error", logger.Field("error", err.Error()), logger.Field("task", task)) - } else { - l.Info("[CreateOrder] Enqueue task success", logger.Field("TaskID", taskInfo.ID)) - } - - return &types.PurchaseOrderResponse{ - OrderNo: orderInfo.OrderNo, - }, nil -} diff --git a/internal/logic/app/order/queryOrderDetailLogic.go b/internal/logic/app/order/queryOrderDetailLogic.go deleted file mode 100644 index 8938445..0000000 --- a/internal/logic/app/order/queryOrderDetailLogic.go +++ /dev/null @@ -1,40 +0,0 @@ -package order - -import ( - "context" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type QueryOrderDetailLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Get order -func NewQueryOrderDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryOrderDetailLogic { - return &QueryOrderDetailLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *QueryOrderDetailLogic) QueryOrderDetail(req *types.QueryOrderDetailRequest) (resp *types.OrderDetail, err error) { - orderInfo, err := l.svcCtx.OrderModel.FindOneDetailsByOrderNo(l.ctx, req.OrderNo) - if err != nil { - l.Error("[QueryOrderDetail] Database query error", logger.Field("error", err.Error()), logger.Field("order_no", req.OrderNo)) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find order error: %v", err.Error()) - } - resp = &types.OrderDetail{} - tool.DeepCopy(resp, orderInfo) - // Prevent commission amount leakage - resp.Commission = 0 - return -} diff --git a/internal/logic/app/order/queryOrderListLogic.go b/internal/logic/app/order/queryOrderListLogic.go deleted file mode 100644 index 275fda3..0000000 --- a/internal/logic/app/order/queryOrderListLogic.go +++ /dev/null @@ -1,56 +0,0 @@ -package order - -import ( - "context" - - "github.com/perfect-panel/server/pkg/constant" - - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type QueryOrderListLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Get order list -func NewQueryOrderListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryOrderListLogic { - return &QueryOrderListLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *QueryOrderListLogic) QueryOrderList(req *types.QueryOrderListRequest) (resp *types.QueryOrderListResponse, err error) { - u, ok := l.ctx.Value(constant.CtxKeyUser).(*user.User) - if !ok { - logger.Error("current user is not found in context") - return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access") - } - total, data, err := l.svcCtx.OrderModel.QueryOrderListByPage(l.ctx, req.Page, req.Size, 0, u.Id, 0, "") - if err != nil { - l.Error("[QueryOrderListLogic] Query order list failed", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Query order list failed") - } - resp = &types.QueryOrderListResponse{ - Total: total, - List: make([]types.OrderDetail, 0), - } - for _, item := range data { - var orderInfo types.OrderDetail - tool.DeepCopy(&orderInfo, item) - // Prevent commission amount leakage - orderInfo.Commission = 0 - resp.List = append(resp.List, orderInfo) - } - - return -} diff --git a/internal/logic/app/order/rechargeLogic.go b/internal/logic/app/order/rechargeLogic.go deleted file mode 100644 index 7e805b8..0000000 --- a/internal/logic/app/order/rechargeLogic.go +++ /dev/null @@ -1,92 +0,0 @@ -package order - -import ( - "context" - "encoding/json" - "time" - - "github.com/perfect-panel/server/pkg/constant" - "github.com/perfect-panel/server/pkg/xerr" - - "github.com/hibiken/asynq" - "github.com/perfect-panel/server/internal/model/order" - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" - queue "github.com/perfect-panel/server/queue/types" - "github.com/pkg/errors" -) - -type RechargeLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// NewRechargeLogic Recharge -func NewRechargeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RechargeLogic { - return &RechargeLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *RechargeLogic) Recharge(req *types.RechargeOrderRequest) (resp *types.RechargeOrderResponse, err error) { - u, ok := l.ctx.Value(constant.CtxKeyUser).(*user.User) - if !ok { - logger.Error("current user is not found in context") - return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access") - } - // find payment method - payment, err := l.svcCtx.PaymentModel.FindOne(l.ctx, req.Payment) - if err != nil { - l.Error("[Recharge] Database query error", logger.Field("error", err.Error()), logger.Field("payment", req.Payment)) - return nil, errors.Wrapf(err, "find payment error: %v", err.Error()) - } - // Calculate the handling fee - feeAmount := calculateFee(req.Amount, payment) - // query user is new purchase or renewal - isNew, err := l.svcCtx.OrderModel.IsUserEligibleForNewOrder(l.ctx, u.Id) - if err != nil { - l.Error("[Recharge] Database query error", logger.Field("error", err.Error()), logger.Field("user_id", u.Id)) - return nil, errors.Wrapf(err, "query user error: %v", err.Error()) - } - orderInfo := order.Order{ - UserId: u.Id, - OrderNo: tool.GenerateTradeNo(), - Type: 4, - Price: req.Amount, - Amount: req.Amount + feeAmount, - FeeAmount: feeAmount, - PaymentId: req.Payment, - Method: payment.Platform, - Status: 1, - IsNew: isNew, - } - err = l.svcCtx.OrderModel.Insert(l.ctx, &orderInfo) - if err != nil { - l.Error("[Recharge] Database insert error", logger.Field("error", err.Error()), logger.Field("order", orderInfo)) - return nil, errors.Wrapf(err, "insert order error: %v", err.Error()) - } - // Deferred task - payload := queue.DeferCloseOrderPayload{ - OrderNo: orderInfo.OrderNo, - } - val, err := json.Marshal(payload) - if err != nil { - l.Error("[Recharge] Marshal payload error", logger.Field("error", err.Error()), logger.Field("payload", payload)) - } - task := asynq.NewTask(queue.DeferCloseOrder, val, asynq.MaxRetry(3)) - taskInfo, err := l.svcCtx.Queue.Enqueue(task, asynq.ProcessIn(CloseOrderTimeMinutes*time.Minute)) - if err != nil { - l.Error("[Recharge] Enqueue task error", logger.Field("error", err.Error()), logger.Field("task", task)) - } else { - l.Info("[Recharge] Enqueue task success", logger.Field("TaskID", taskInfo.ID)) - } - return &types.RechargeOrderResponse{ - OrderNo: orderInfo.OrderNo, - }, nil -} diff --git a/internal/logic/app/order/renewalLogic.go b/internal/logic/app/order/renewalLogic.go deleted file mode 100644 index 5571a66..0000000 --- a/internal/logic/app/order/renewalLogic.go +++ /dev/null @@ -1,178 +0,0 @@ -package order - -import ( - "context" - "encoding/json" - "time" - - "github.com/perfect-panel/server/pkg/constant" - - "github.com/hibiken/asynq" - "github.com/perfect-panel/server/internal/model/order" - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/xerr" - queue "github.com/perfect-panel/server/queue/types" - "github.com/pkg/errors" - "gorm.io/gorm" -) - -type RenewalLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Renewal Subscription -func NewRenewalLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RenewalLogic { - return &RenewalLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *RenewalLogic) Renewal(req *types.RenewalOrderRequest) (resp *types.RenewalOrderResponse, err error) { - u, ok := l.ctx.Value(constant.CtxKeyUser).(*user.User) - if !ok { - logger.Error("current user is not found in context") - return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access") - } - orderNo := tool.GenerateTradeNo() - // find user subscribe - userSubscribe, err := l.svcCtx.UserModel.FindOneUserSubscribe(l.ctx, req.UserSubscribeID) - if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find user subscribe error: %v", err.Error()) - } - // find subscription - sub, err := l.svcCtx.SubscribeModel.FindOne(l.ctx, userSubscribe.SubscribeId) - if err != nil { - l.Error("[Renewal] Database query error", logger.Field("error", err.Error()), logger.Field("subscribe_id", userSubscribe.SubscribeId)) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find subscribe error: %v", err.Error()) - } - // check subscribe plan status - if !*sub.Sell { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "subscribe not sell") - } - var discount float64 = 1 - if sub.Discount != "" { - var dis []types.SubscribeDiscount - _ = json.Unmarshal([]byte(sub.Discount), &dis) - discount = getDiscount(dis, req.Quantity) - } - price := sub.UnitPrice * req.Quantity - amount := int64(float64(price) * discount) - discountAmount := price - amount - var coupon int64 = 0 - if req.Coupon != "" { - couponInfo, err := l.svcCtx.CouponModel.FindOneByCode(l.ctx, req.Coupon) - if err != nil { - l.Error("[Renewal] Database query error", logger.Field("error", err.Error()), logger.Field("coupon", req.Coupon)) - return nil, errors.Wrapf(err, "find coupon error: %v", err.Error()) - } - if couponInfo.Count <= couponInfo.UsedCount { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.CouponInsufficientUsage), "coupon used") - } - coupon = calculateCoupon(amount, couponInfo) - } - payment, err := l.svcCtx.PaymentModel.FindOne(l.ctx, req.Payment) - if err != nil { - l.Error("[Renewal] Database query error", logger.Field("error", err.Error()), logger.Field("payment", req.Payment)) - return nil, errors.Wrapf(err, "find payment error: %v", err.Error()) - } - amount -= coupon - - var deductionAmount int64 - // Check user deduction amount - if u.GiftAmount > 0 { - if u.GiftAmount >= amount { - deductionAmount = amount - amount = 0 - u.GiftAmount -= amount - } else { - deductionAmount = u.GiftAmount - amount -= u.GiftAmount - u.GiftAmount = 0 - } - } - - var feeAmount int64 - // Calculate the handling fee - if amount > 0 { - feeAmount = calculateFee(amount, payment) - } - - amount += feeAmount - - // create order - orderInfo := order.Order{ - UserId: u.Id, - ParentId: userSubscribe.OrderId, - OrderNo: orderNo, - Type: 2, - Quantity: req.Quantity, - Price: price, - Amount: amount, - GiftAmount: deductionAmount, - Discount: discountAmount, - Coupon: req.Coupon, - CouponDiscount: coupon, - PaymentId: payment.Id, - Method: payment.Platform, - FeeAmount: feeAmount, - Status: 1, - SubscribeId: userSubscribe.SubscribeId, - SubscribeToken: userSubscribe.Token, - } - // Database transaction - err = l.svcCtx.DB.Transaction(func(db *gorm.DB) error { - // update user deduction && Pre deduction ,Return after canceling the order - if orderInfo.GiftAmount > 0 { - // update user deduction && Pre deduction ,Return after canceling the order - if err := l.svcCtx.UserModel.Update(l.ctx, u, db); err != nil { - l.Error("[Purchase] Database update error", logger.Field("error", err.Error()), logger.Field("user", u)) - return err - } - // create deduction record - deductionLog := user.GiftAmountLog{ - UserId: orderInfo.UserId, - OrderNo: orderInfo.OrderNo, - Amount: orderInfo.GiftAmount, - Type: 2, - Balance: u.GiftAmount, - Remark: "Renewal order deduction", - } - if err := db.Model(&user.GiftAmountLog{}).Create(&deductionLog).Error; err != nil { - l.Error("[Renewal] Database insert error", logger.Field("error", err.Error()), logger.Field("deductionLog", deductionLog)) - return err - } - } - // insert order - return db.Model(&order.Order{}).Create(&orderInfo).Error - }) - if err != nil { - l.Error("[Renewal] Database insert error", logger.Field("error", err.Error()), logger.Field("order", orderInfo)) - return nil, errors.Wrapf(err, "insert order error: %v", err.Error()) - } - // Deferred task - payload := queue.DeferCloseOrderPayload{ - OrderNo: orderInfo.OrderNo, - } - val, err := json.Marshal(payload) - if err != nil { - l.Error("[Renewal] Marshal payload error", logger.Field("error", err.Error()), logger.Field("payload", payload)) - } - task := asynq.NewTask(queue.DeferCloseOrder, val, asynq.MaxRetry(3)) - taskInfo, err := l.svcCtx.Queue.Enqueue(task, asynq.ProcessIn(CloseOrderTimeMinutes*time.Minute)) - if err != nil { - l.Error("[Renewal] Enqueue task error", logger.Field("error", err.Error()), logger.Field("task", task)) - } else { - l.Info("[Renewal] Enqueue task success", logger.Field("TaskID", taskInfo.ID)) - } - return &types.RenewalOrderResponse{ - OrderNo: orderInfo.OrderNo, - }, nil -} diff --git a/internal/logic/app/order/resetTrafficLogic.go b/internal/logic/app/order/resetTrafficLogic.go deleted file mode 100644 index 9d1f60f..0000000 --- a/internal/logic/app/order/resetTrafficLogic.go +++ /dev/null @@ -1,146 +0,0 @@ -package order - -import ( - "context" - "encoding/json" - "time" - - "github.com/perfect-panel/server/pkg/constant" - "github.com/perfect-panel/server/pkg/xerr" - - "gorm.io/gorm" - - "github.com/hibiken/asynq" - "github.com/perfect-panel/server/internal/model/order" - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/pkg/tool" - queue "github.com/perfect-panel/server/queue/types" - "github.com/pkg/errors" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" -) - -type ResetTrafficLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Reset traffic -func NewResetTrafficLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ResetTrafficLogic { - return &ResetTrafficLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *ResetTrafficLogic) ResetTraffic(req *types.ResetTrafficOrderRequest) (resp *types.ResetTrafficOrderResponse, err error) { - u, ok := l.ctx.Value(constant.CtxKeyUser).(*user.User) - if !ok { - logger.Error("current user is not found in context") - return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access") - } - // find user subscription - userSubscribe, err := l.svcCtx.UserModel.FindOneUserSubscribe(l.ctx, req.UserSubscribeID) - if err != nil { - l.Error("[ResetTraffic] Database query error", logger.Field("error", err.Error()), logger.Field("UserSubscribeID", req.UserSubscribeID)) - return nil, errors.Wrapf(err, "find user subscribe error: %v", err.Error()) - } - if userSubscribe.Subscribe == nil { - l.Error("[ResetTraffic] subscribe not found", logger.Field("UserSubscribeID", req.UserSubscribeID)) - return nil, errors.New("subscribe not found") - } - amount := userSubscribe.Subscribe.Replacement - var deductionAmount int64 - // Check user deduction amount - if u.GiftAmount > 0 { - if u.GiftAmount >= amount { - deductionAmount = amount - amount = 0 - u.GiftAmount -= amount - } else { - deductionAmount = u.GiftAmount - amount -= u.GiftAmount - u.GiftAmount = 0 - } - } - // find payment method - payment, err := l.svcCtx.PaymentModel.FindOne(l.ctx, req.Payment) - if err != nil { - l.Error("[ResetTraffic] Database query error", logger.Field("error", err.Error()), logger.Field("payment", req.Payment)) - return nil, errors.Wrapf(err, "find payment error: %v", err.Error()) - } - var feeAmount int64 - // Calculate the handling fee - if amount > 0 { - feeAmount = calculateFee(amount, payment) - } - // create order - orderInfo := order.Order{ - Id: 0, - ParentId: userSubscribe.OrderId, - UserId: u.Id, - OrderNo: tool.GenerateTradeNo(), - Type: 3, - Price: userSubscribe.Subscribe.Replacement, - Amount: amount + feeAmount, - GiftAmount: deductionAmount, - FeeAmount: feeAmount, - PaymentId: req.Payment, - Method: payment.Platform, - Status: 1, - SubscribeId: userSubscribe.SubscribeId, - SubscribeToken: userSubscribe.Token, - } - // Database transaction - err = l.svcCtx.DB.Transaction(func(db *gorm.DB) error { - // update user deduction && Pre deduction ,Return after canceling the order - if orderInfo.GiftAmount > 0 { - // update user deduction && Pre deduction ,Return after canceling the order - if err := l.svcCtx.UserModel.Update(l.ctx, u, db); err != nil { - l.Error("[ResetTraffic] Database update error", logger.Field("error", err.Error()), logger.Field("user", u)) - return err - } - // create deduction record - deductionLog := user.GiftAmountLog{ - UserId: orderInfo.UserId, - OrderNo: orderInfo.OrderNo, - Amount: orderInfo.GiftAmount, - Type: 2, - Balance: u.GiftAmount, - Remark: "ResetTraffic order deduction", - } - if err := db.Model(&user.GiftAmountLog{}).Create(&deductionLog).Error; err != nil { - l.Error("[ResetTraffic] Database insert error", logger.Field("error", err.Error()), logger.Field("deductionLog", deductionLog)) - return err - } - } - // insert order - return db.Model(&order.Order{}).Create(&orderInfo).Error - }) - if err != nil { - l.Error("[ResetTraffic] Database insert error", logger.Field("error", err.Error()), logger.Field("order", orderInfo)) - return nil, errors.Wrapf(err, "insert order error: %v", err.Error()) - } - // Deferred task - payload := queue.DeferCloseOrderPayload{ - OrderNo: orderInfo.OrderNo, - } - val, err := json.Marshal(payload) - if err != nil { - l.Error("[ResetTraffic] Marshal payload error", logger.Field("error", err.Error()), logger.Field("payload", payload)) - } - task := asynq.NewTask(queue.DeferCloseOrder, val, asynq.MaxRetry(3)) - taskInfo, err := l.svcCtx.Queue.Enqueue(task, asynq.ProcessIn(CloseOrderTimeMinutes*time.Minute)) - if err != nil { - l.Error("[ResetTraffic] Enqueue task error", logger.Field("error", err.Error()), logger.Field("task", task)) - } else { - l.Info("[ResetTraffic] Enqueue task success", logger.Field("TaskID", taskInfo.ID)) - } - return &types.ResetTrafficOrderResponse{ - OrderNo: orderInfo.OrderNo, - }, nil -} diff --git a/internal/logic/app/payment/getAvailablePaymentMethodsLogic.go b/internal/logic/app/payment/getAvailablePaymentMethodsLogic.go deleted file mode 100644 index 79ea7e0..0000000 --- a/internal/logic/app/payment/getAvailablePaymentMethodsLogic.go +++ /dev/null @@ -1,40 +0,0 @@ -package payment - -import ( - "context" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type GetAvailablePaymentMethodsLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// NewGetAvailablePaymentMethodsLogic Get available payment methods -func NewGetAvailablePaymentMethodsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetAvailablePaymentMethodsLogic { - return &GetAvailablePaymentMethodsLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *GetAvailablePaymentMethodsLogic) GetAvailablePaymentMethods() (resp *types.GetAvailablePaymentMethodsResponse, err error) { - data, err := l.svcCtx.PaymentModel.FindAvailableMethods(l.ctx) - if err != nil { - l.Error("[GetAvailablePaymentMethods] database error", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "GetAvailablePaymentMethods: %v", err.Error()) - } - resp = &types.GetAvailablePaymentMethodsResponse{ - List: make([]types.PaymentMethod, 0), - } - tool.DeepCopy(&resp.List, data) - return -} diff --git a/internal/logic/app/subscribe/queryApplicationConfigLogic.go b/internal/logic/app/subscribe/queryApplicationConfigLogic.go deleted file mode 100644 index a76337f..0000000 --- a/internal/logic/app/subscribe/queryApplicationConfigLogic.go +++ /dev/null @@ -1,115 +0,0 @@ -package subscribe - -import ( - "context" - - "github.com/perfect-panel/server/internal/model/application" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - "gorm.io/gorm" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" -) - -type QueryApplicationConfigLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Get application config -func NewQueryApplicationConfigLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryApplicationConfigLogic { - return &QueryApplicationConfigLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *QueryApplicationConfigLogic) QueryApplicationConfig() (resp *types.ApplicationResponse, err error) { - resp = &types.ApplicationResponse{} - var applications []*application.Application - err = l.svcCtx.ApplicationModel.Transaction(l.ctx, func(tx *gorm.DB) (err error) { - return tx.Model(applications).Preload("ApplicationVersions").Find(&applications).Error - }) - if err != nil { - l.Errorw("[QueryApplicationConfig] get application error: ", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "get application error: %v", err.Error()) - } - - if len(applications) == 0 { - return resp, nil - } - - for _, app := range applications { - applicationResponse := types.ApplicationResponseInfo{ - Id: app.Id, - Name: app.Name, - Icon: app.Icon, - Description: app.Description, - SubscribeType: app.SubscribeType, - } - applicationVersions := app.ApplicationVersions - if len(applicationVersions) != 0 { - for _, applicationVersion := range applicationVersions { - /*if !applicationVersion.IsDefault { - continue - }*/ - switch applicationVersion.Platform { - case "ios": - applicationResponse.Platform.IOS = append(applicationResponse.Platform.IOS, &types.ApplicationVersion{ - Id: applicationVersion.Id, - Url: applicationVersion.Url, - Version: applicationVersion.Version, - IsDefault: applicationVersion.IsDefault, - Description: applicationVersion.Description, - }) - case "macos": - applicationResponse.Platform.MacOS = append(applicationResponse.Platform.MacOS, &types.ApplicationVersion{ - Id: applicationVersion.Id, - Url: applicationVersion.Url, - Version: applicationVersion.Version, - IsDefault: applicationVersion.IsDefault, - Description: applicationVersion.Description, - }) - case "linux": - applicationResponse.Platform.Linux = append(applicationResponse.Platform.Linux, &types.ApplicationVersion{ - Id: applicationVersion.Id, - Url: applicationVersion.Url, - Version: applicationVersion.Version, - IsDefault: applicationVersion.IsDefault, - Description: applicationVersion.Description, - }) - case "android": - applicationResponse.Platform.Android = append(applicationResponse.Platform.Android, &types.ApplicationVersion{ - Id: applicationVersion.Id, - Url: applicationVersion.Url, - Version: applicationVersion.Version, - IsDefault: applicationVersion.IsDefault, - Description: applicationVersion.Description, - }) - case "windows": - applicationResponse.Platform.Windows = append(applicationResponse.Platform.Windows, &types.ApplicationVersion{ - Id: applicationVersion.Id, - Url: applicationVersion.Url, - Version: applicationVersion.Version, - IsDefault: applicationVersion.IsDefault, - Description: applicationVersion.Description, - }) - case "harmony": - applicationResponse.Platform.Harmony = append(applicationResponse.Platform.Harmony, &types.ApplicationVersion{ - Id: applicationVersion.Id, - Url: applicationVersion.Url, - Version: applicationVersion.Version, - IsDefault: applicationVersion.IsDefault, - Description: applicationVersion.Description, - }) - } - } - } - resp.Applications = append(resp.Applications, applicationResponse) - } - return -} diff --git a/internal/logic/app/subscribe/querySubscribeGroupListLogic.go b/internal/logic/app/subscribe/querySubscribeGroupListLogic.go deleted file mode 100644 index 0f7c947..0000000 --- a/internal/logic/app/subscribe/querySubscribeGroupListLogic.go +++ /dev/null @@ -1,44 +0,0 @@ -package subscribe - -import ( - "context" - - "github.com/perfect-panel/server/internal/model/subscribe" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type QuerySubscribeGroupListLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Get subscribe group list -func NewQuerySubscribeGroupListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QuerySubscribeGroupListLogic { - return &QuerySubscribeGroupListLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *QuerySubscribeGroupListLogic) QuerySubscribeGroupList() (resp *types.QuerySubscribeGroupListResponse, err error) { - var list []*subscribe.Group - var total int64 - err = l.svcCtx.DB.Model(&subscribe.Group{}).Count(&total).Find(&list).Error - if err != nil { - l.Logger.Error("[QuerySubscribeGroupListLogic] get subscribe group list failed: ", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "get subscribe group list failed: %v", err.Error()) - } - groupList := make([]types.SubscribeGroup, 0) - tool.DeepCopy(&groupList, list) - return &types.QuerySubscribeGroupListResponse{ - Total: total, - List: groupList, - }, nil -} diff --git a/internal/logic/app/subscribe/querySubscribeListLogic.go b/internal/logic/app/subscribe/querySubscribeListLogic.go deleted file mode 100644 index 474376a..0000000 --- a/internal/logic/app/subscribe/querySubscribeListLogic.go +++ /dev/null @@ -1,55 +0,0 @@ -package subscribe - -import ( - "context" - "encoding/json" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type QuerySubscribeListLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Get subscribe list -func NewQuerySubscribeListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QuerySubscribeListLogic { - return &QuerySubscribeListLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *QuerySubscribeListLogic) QuerySubscribeList() (resp *types.QuerySubscribeListResponse, err error) { - - data, err := l.svcCtx.SubscribeModel.QuerySubscribeList(l.ctx) - if err != nil { - l.Errorw("[QuerySubscribeListLogic] Database Error", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "QuerySubscribeList error: %v", err.Error()) - } - resp = &types.QuerySubscribeListResponse{ - List: make([]types.Subscribe, 0), - Total: int64(len(data)), - } - for _, v := range data { - var sub types.Subscribe - tool.DeepCopy(&sub, v) - if v.Discount != "" { - if err = json.Unmarshal([]byte(v.Discount), &sub.Discount); err != nil { - l.Errorw("[QuerySubscribeListLogic] json.Unmarshal Error", logger.Field("error", err.Error()), logger.Field("value", v.Discount)) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "json.Unmarshal error: %v", err.Error()) - } - } else { - sub.Discount = make([]types.SubscribeDiscount, 0) - } - resp.List = append(resp.List, sub) - } - return -} diff --git a/internal/logic/app/subscribe/queryUserAlreadySubscribeLogic.go b/internal/logic/app/subscribe/queryUserAlreadySubscribeLogic.go deleted file mode 100644 index b25e110..0000000 --- a/internal/logic/app/subscribe/queryUserAlreadySubscribeLogic.go +++ /dev/null @@ -1,67 +0,0 @@ -package subscribe - -import ( - "context" - - "github.com/perfect-panel/server/internal/model/order" - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/constant" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - "gorm.io/gorm" -) - -type QueryUserAlreadySubscribeLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Get Already subscribed to package -func NewQueryUserAlreadySubscribeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryUserAlreadySubscribeLogic { - return &QueryUserAlreadySubscribeLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *QueryUserAlreadySubscribeLogic) QueryUserAlreadySubscribe() (resp *types.QueryUserSubscribeResp, err error) { - resp = &types.QueryUserSubscribeResp{ - Data: make([]types.UserSubscribeData, 0), - } - userInfo := l.ctx.Value(constant.CtxKeyUser).(*user.User) - var orderIds []int64 - var subscribes []user.Subscribe - err = l.svcCtx.OrderModel.Transaction(context.Background(), func(tx *gorm.DB) error { - if err := tx.Model(&order.Order{}).Where("user_id = ? AND status in ?", userInfo.Id, []int64{2, 5}).Select("id").Find(&orderIds).Error; err != nil { - return err - } - if len(orderIds) == 0 { - return nil - } - return tx.Model(&user.Subscribe{}).Where("user_id = ? AND order_id in ?", userInfo.Id, orderIds).Order("created_at desc").Find(&subscribes).Error - }) - if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find order error: %v", err.Error()) - } - if len(subscribes) == 0 { - return - } - - userAlreadySubscribe := make(map[int64]int64) - for _, subscribe := range subscribes { - userAlreadySubscribe[subscribe.SubscribeId] = subscribe.Id - } - - for k, v := range userAlreadySubscribe { - resp.Data = append(resp.Data, types.UserSubscribeData{ - SubscribeId: k, - UserSubscribeId: v, - }) - } - return -} diff --git a/internal/logic/app/subscribe/queryUserAvailableUserSubscribeLogic.go b/internal/logic/app/subscribe/queryUserAvailableUserSubscribeLogic.go deleted file mode 100644 index be67b99..0000000 --- a/internal/logic/app/subscribe/queryUserAvailableUserSubscribeLogic.go +++ /dev/null @@ -1,107 +0,0 @@ -package subscribe - -import ( - "context" - "strconv" - "strings" - "time" - - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/constant" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type QueryUserAvailableUserSubscribeLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Get Available subscriptions for users -func NewQueryUserAvailableUserSubscribeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryUserAvailableUserSubscribeLogic { - return &QueryUserAvailableUserSubscribeLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *QueryUserAvailableUserSubscribeLogic) QueryUserAvailableUserSubscribe(req *types.AppUserSubscribeRequest) (resp *types.AppUserSubscbribeResponse, err error) { - resp = &types.AppUserSubscbribeResponse{List: make([]types.AppUserSubcbribe, 0)} - userInfo := l.ctx.Value(constant.CtxKeyUser).(*user.User) - //查询用户订阅 - subscribeDetails, err := l.svcCtx.UserModel.QueryUserSubscribe(l.ctx, userInfo.Id, 1, 2) - if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "get query user subscribe error: %v", err.Error()) - } - - userSubscribeMap := make(map[int64]types.AppUserSubcbribe) - for _, sd := range subscribeDetails { - userSubscribeInfo := types.AppUserSubcbribe{ - Id: sd.Id, - Name: sd.Subscribe.Name, - Traffic: sd.Traffic, - Upload: sd.Upload, - Download: sd.Download, - ExpireTime: sd.ExpireTime.Format(time.DateTime), - StartTime: sd.StartTime.Format(time.DateTime), - DeviceLimit: sd.Subscribe.DeviceLimit, - } - - //不需要查询节点 - if req.ContainsNodes == nil || !*req.ContainsNodes { - resp.List = append(resp.List, userSubscribeInfo) - continue - } - - //拿到所有订阅下的服务组id - var ids []int64 - for _, idStr := range strings.Split(sd.Subscribe.ServerGroup, ",") { - id, err := strconv.ParseInt(idStr, 10, 64) - if err != nil { - continue - } - ids = append(ids, id) - } - //根据服务组id拿到所有节点 - servers, err := l.svcCtx.ServerModel.FindServerListByGroupIds(l.ctx, ids) - if err != nil { - l.Logger.Errorf("FindServerListByGroupIds error: %v", err.Error()) - continue - } - - for _, server := range servers { - userSubscribeInfo.List = append(userSubscribeInfo.List, types.AppUserSubscbribeNode{ - Id: server.Id, - Uuid: sd.UUID, - Traffic: sd.Traffic, - Upload: sd.Upload, - Download: sd.Download, - RelayNode: server.RelayNode, - RelayMode: server.RelayMode, - Longitude: server.Longitude, - Latitude: server.Latitude, - Tags: strings.Split(server.Tags, ","), - Config: server.Config, - ServerAddr: server.ServerAddr, - Protocol: server.Protocol, - SpeedLimit: server.SpeedLimit, - City: server.City, - Country: server.Country, - Name: server.Name, - }) - } - resp.List = append(resp.List, userSubscribeInfo) - userSubscribeMap[userSubscribeInfo.Id] = userSubscribeInfo - } - - for _, userSubscribeInfo := range userSubscribeMap { - resp.List = append(resp.List, userSubscribeInfo) - } - return resp, nil - -} diff --git a/internal/logic/app/subscribe/resetUserSubscribePeriodLogic.go b/internal/logic/app/subscribe/resetUserSubscribePeriodLogic.go deleted file mode 100644 index edbc5fb..0000000 --- a/internal/logic/app/subscribe/resetUserSubscribePeriodLogic.go +++ /dev/null @@ -1,60 +0,0 @@ -package subscribe - -import ( - "context" - "time" - - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/constant" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type ResetUserSubscribePeriodLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -func NewResetUserSubscribePeriodLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ResetUserSubscribePeriodLogic { - return &ResetUserSubscribePeriodLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *ResetUserSubscribePeriodLogic) ResetUserSubscribePeriod(req *types.UserSubscribeResetPeriodRequest) (resp *types.UserSubscribeResetPeriodResponse, err error) { - resp = &types.UserSubscribeResetPeriodResponse{} - userInfo := l.ctx.Value(constant.CtxKeyUser).(*user.User) - subscribe, err := l.svcCtx.UserModel.FindOneSubscribe(l.ctx, req.UserSubscribeId) - if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find order error: %v", err.Error()) - } - if userInfo.Id != subscribe.UserId { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SubscribeNotAvailable), "user not authorized,subscribe not available") - } - - if time.Now().After(subscribe.ExpireTime) { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SubscribeExpired), "subscribe expired") - } - - if subscribe.Traffic < 1 { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.ExistAvailableTraffic), "Unlimited data plan.") - } - - if (subscribe.Download + subscribe.Upload + 10240) < subscribe.Traffic { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.ExistAvailableTraffic), "There is still available traffic.") - } - - subscribe.ExpireTime = subscribe.ExpireTime.AddDate(0, -1, 0) - err = l.svcCtx.UserModel.UpdateSubscribe(l.ctx, subscribe) - if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "update subscribe error: %v", err.Error()) - } - resp.Status = true - return -} diff --git a/internal/logic/app/user/deleteAccountLogic.go b/internal/logic/app/user/deleteAccountLogic.go deleted file mode 100644 index c666fb4..0000000 --- a/internal/logic/app/user/deleteAccountLogic.go +++ /dev/null @@ -1,103 +0,0 @@ -package user - -import ( - "context" - "encoding/json" - "fmt" - - "github.com/perfect-panel/server/internal/config" - "github.com/perfect-panel/server/internal/logic/common" - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/constant" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type DeleteAccountLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Delete Account -func NewDeleteAccountLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteAccountLogic { - return &DeleteAccountLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *DeleteAccountLogic) DeleteAccount(req *types.DeleteAccountRequest) error { - userInfo, exists := l.ctx.Value(constant.CtxKeyUser).(user.User) - if !exists { - return nil - } - - var account string - for _, authMethod := range userInfo.AuthMethods { - if authMethod.AuthType == req.Method { - account = authMethod.AuthIdentifier - break - } - } - if account == "" { - return nil - } - - if req.Method == "email" { - emailConfig := l.svcCtx.Config.Email - - if !emailConfig.Enable { - return errors.Wrapf(xerr.NewErrCode(xerr.EmailNotEnabled), "Email function is not enabled yet") - } - - if emailConfig.EnableVerify { - cacheKey := fmt.Sprintf("%s:%s:%s", config.AuthCodeCacheKey, constant.Security, account) - value, err := l.svcCtx.Redis.Get(l.ctx, cacheKey).Result() - if err != nil { - l.Errorw("Redis Error", logger.Field("error", err.Error()), logger.Field("cacheKey", cacheKey)) - return errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error") - } - - var payload common.CacheKeyPayload - err = json.Unmarshal([]byte(value), &payload) - if err != nil { - l.Errorw("Unmarshal Error", logger.Field("error", err.Error()), logger.Field("value", value)) - return errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error") - } - - if payload.Code != req.Code { - return errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error") - } - } - } else { - cacheKey := fmt.Sprintf("%s:%s:%s", config.AuthCodeTelephoneCacheKey, constant.Security, account) - value, err := l.svcCtx.Redis.Get(l.ctx, cacheKey).Result() - if err != nil { - l.Errorw("Redis Error", logger.Field("error", err.Error()), logger.Field("cacheKey", cacheKey)) - return errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error") - } - - if value == "" { - return errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error") - } - - var payload common.CacheKeyPayload - if err := json.Unmarshal([]byte(value), &payload); err != nil { - l.Errorw("[SendSmsCode]: Unmarshal Error", logger.Field("error", err.Error()), logger.Field("value", value)) - } - if payload.Code != req.Code { - return errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error") - } - } - err := l.svcCtx.UserModel.Delete(l.ctx, userInfo.Id) - if err != nil { - l.Errorw("update user password error", logger.Field("error", err.Error())) - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "update user password") - } - return nil -} diff --git a/internal/logic/app/user/getuseronlinetimestatisticslogic.go b/internal/logic/app/user/getuseronlinetimestatisticslogic.go deleted file mode 100644 index bc293b5..0000000 --- a/internal/logic/app/user/getuseronlinetimestatisticslogic.go +++ /dev/null @@ -1,115 +0,0 @@ -package user - -import ( - "context" - "sort" - "time" - - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/constant" - "github.com/perfect-panel/server/pkg/logger" -) - -type GetUserOnlineTimeStatisticsLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Get user online time total -func NewGetUserOnlineTimeStatisticsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserOnlineTimeStatisticsLogic { - return &GetUserOnlineTimeStatisticsLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *GetUserOnlineTimeStatisticsLogic) GetUserOnlineTimeStatistics() (resp *types.GetUserOnlineTimeStatisticsResponse, err error) { - u := l.ctx.Value(constant.CtxKeyUser).(*user.User) - //获取历史最长在线时间 - var OnlineSeconds int64 - if err := l.svcCtx.DB.Model(user.DeviceOnlineRecord{}).Where("user_id = ?", u.Id).Select("online_seconds").Order("online_seconds desc").Limit(1).Scan(&OnlineSeconds).Error; err != nil { - l.Logger.Error(err) - } - - //获取历史连续最长在线天数 - var DurationDays int64 - if err := l.svcCtx.DB.Model(user.DeviceOnlineRecord{}).Where("user_id = ?", u.Id).Select("duration_days").Order("duration_days desc").Limit(1).Scan(&DurationDays).Error; err != nil { - l.Logger.Error(err) - } - - //获取近七天在线情况 - var userOnlineRecord []user.DeviceOnlineRecord - if err := l.svcCtx.DB.Model(&userOnlineRecord).Where("user_id = ? and created_at >= ?", u.Id, time.Now().AddDate(0, 0, -7).Format(time.DateTime)).Order("created_at desc").Find(&userOnlineRecord).Error; err != nil { - l.Logger.Error(err) - } - - //获取当前连续在线天数 - var currentContinuousDays int64 - if len(userOnlineRecord) > 0 { - currentContinuousDays = userOnlineRecord[0].DurationDays - } else { - currentContinuousDays = 1 - } - - var dates []string - for i := 0; i < 7; i++ { - date := time.Now().AddDate(0, 0, -i).Format(time.DateOnly) - dates = append(dates, date) - } - - onlineDays := make(map[string]types.WeeklyStat) - for _, record := range userOnlineRecord { - //获取近七天在线情况 - onlineTime := record.OnlineTime.Format(time.DateOnly) - if weeklyStat, ok := onlineDays[onlineTime]; ok { - weeklyStat.Hours += float64(record.OnlineSeconds) - onlineDays[onlineTime] = weeklyStat - } else { - onlineDays[onlineTime] = types.WeeklyStat{ - Hours: float64(record.OnlineSeconds), - //根据日期获取周几 - DayName: record.OnlineTime.Weekday().String(), - } - } - } - - //补全不存在的日期 - for _, date := range dates { - if _, ok := onlineDays[date]; !ok { - onlineTime, _ := time.Parse(time.DateOnly, date) - onlineDays[date] = types.WeeklyStat{ - DayName: onlineTime.Weekday().String(), - } - } - } - - var keys []string - for key := range onlineDays { - keys = append(keys, key) - } - - //排序 - sort.Strings(keys) - - var weeklyStats []types.WeeklyStat - for index, key := range keys { - weeklyStat := onlineDays[key] - weeklyStat.Day = index + 1 - weeklyStat.Hours = weeklyStat.Hours / float64(3600) - weeklyStats = append(weeklyStats, weeklyStat) - } - - resp = &types.GetUserOnlineTimeStatisticsResponse{ - WeeklyStats: weeklyStats, - ConnectionRecords: types.ConnectionRecords{ - CurrentContinuousDays: currentContinuousDays, - HistoryContinuousDays: DurationDays, - LongestSingleConnection: OnlineSeconds / 60, - }, - } - return -} diff --git a/internal/logic/app/user/getusersubscribetrafficlogslogic.go b/internal/logic/app/user/getusersubscribetrafficlogslogic.go deleted file mode 100644 index b7c5aca..0000000 --- a/internal/logic/app/user/getusersubscribetrafficlogslogic.go +++ /dev/null @@ -1,85 +0,0 @@ -package user - -import ( - "context" - "time" - - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - - "github.com/perfect-panel/server/internal/model/traffic" - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/constant" - "github.com/perfect-panel/server/pkg/logger" - "gorm.io/gorm" -) - -type GetUserSubscribeTrafficLogsLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Get user subcribe traffic logs -func NewGetUserSubscribeTrafficLogsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserSubscribeTrafficLogsLogic { - return &GetUserSubscribeTrafficLogsLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *GetUserSubscribeTrafficLogsLogic) GetUserSubscribeTrafficLogs(req *types.GetUserSubscribeTrafficLogsRequest) (resp *types.GetUserSubscribeTrafficLogsResponse, err error) { - resp = &types.GetUserSubscribeTrafficLogsResponse{} - u := l.ctx.Value(constant.CtxKeyUser).(*user.User) - var traffics []traffic.TrafficLog - err = l.svcCtx.UserModel.Transaction(l.ctx, func(db *gorm.DB) error { - return db.Model(traffic.TrafficLog{}).Where("user_id = ? and `timestamp` >= ? and `timestamp` < ?", u.Id, time.UnixMilli(req.StartTime), time.UnixMilli(req.EndTime)).Find(&traffics).Error - }) - - if err != nil { - l.Errorw("get user subscribe traffic logs failed", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), err.Error()) - } - - //合并多条记录为以天为单位 - trafficMap := make(map[string]*traffic.TrafficLog) - for _, traf := range traffics { - key := traf.Timestamp.Format(time.DateOnly) - existTraf := trafficMap[key] - if existTraf == nil { - trafficMap[key] = &traf - } else { - existTraf.Upload = existTraf.Download + traf.Upload - existTraf.Download = existTraf.Download + traf.Download - trafficMap[key] = existTraf - } - } - - startTime := time.UnixMilli(req.StartTime) - EndTime := time.UnixMilli(req.EndTime) - res := make(map[string]traffic.TrafficLog) - - // 循环遍历每一天 - for current := startTime; !current.After(EndTime); current = current.AddDate(0, 0, 1) { - dateStr := current.Format(time.DateOnly) // 格式化为日期字符串 - if trafficMap[dateStr] == nil { - res[dateStr] = traffic.TrafficLog{ - Timestamp: current, - } - } else { - res[dateStr] = *trafficMap[dateStr] - } - resp.List = append(resp.List, types.TrafficLog{ - Id: res[dateStr].Id, - ServerId: res[dateStr].ServerId, - Upload: res[dateStr].Upload, - Download: res[dateStr].Download, - Timestamp: res[dateStr].Timestamp.UnixMilli(), - }) - } - - return -} diff --git a/internal/logic/app/user/queryUserAffiliateListLogic.go b/internal/logic/app/user/queryUserAffiliateListLogic.go deleted file mode 100644 index 02319eb..0000000 --- a/internal/logic/app/user/queryUserAffiliateListLogic.go +++ /dev/null @@ -1,62 +0,0 @@ -package user - -import ( - "context" - - "github.com/perfect-panel/server/pkg/constant" - - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - "gorm.io/gorm" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" -) - -type QueryUserAffiliateListLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Query User Affiliate List -func NewQueryUserAffiliateListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryUserAffiliateListLogic { - return &QueryUserAffiliateListLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *QueryUserAffiliateListLogic) QueryUserAffiliateList(req *types.QueryUserAffiliateListRequest) (resp *types.QueryUserAffiliateListResponse, err error) { - u, ok := l.ctx.Value(constant.CtxKeyUser).(*user.User) - if !ok { - logger.Error("current user is not found in context") - return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access") - } - var data []*user.User - var total int64 - err = l.svcCtx.UserModel.Transaction(l.ctx, func(db *gorm.DB) error { - return db.Model(&user.User{}).Order("id desc").Where("referer_id = ?", u.Id).Count(&total).Limit(req.Size).Offset((req.Page - 1) * req.Size).Find(&data).Error - }) - if err != nil { - l.Errorw("Query User Affiliate List failed: %v", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Query User Affiliate List failed: %v", err.Error()) - } - - list := make([]types.UserAffiliate, 0) - for _, item := range data { - list = append(list, types.UserAffiliate{ - //Email: tool.MaskEmail(item.Email), - Avatar: item.Avatar, - RegisteredAt: item.CreatedAt.UnixMilli(), - Enable: *item.Enable, - }) - } - return &types.QueryUserAffiliateListResponse{ - Total: total, - List: list, - }, nil -} diff --git a/internal/logic/app/user/queryUserInfoLogic.go b/internal/logic/app/user/queryUserInfoLogic.go deleted file mode 100644 index 9bc70e7..0000000 --- a/internal/logic/app/user/queryUserInfoLogic.go +++ /dev/null @@ -1,63 +0,0 @@ -package user - -import ( - "context" - - "github.com/perfect-panel/server/pkg/constant" - - "github.com/perfect-panel/server/internal/model/user" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" -) - -type QueryUserInfoLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// query user info -func NewQueryUserInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryUserInfoLogic { - return &QueryUserInfoLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *QueryUserInfoLogic) QueryUserInfo() (resp *types.UserInfoResponse, err error) { - u := l.ctx.Value(constant.CtxKeyUser).(*user.User) - var devices []types.UserDevice - if len(u.UserDevices) != 0 { - for _, device := range u.UserDevices { - devices = append(devices, types.UserDevice{ - Id: device.Id, - Identifier: device.Identifier, - Online: device.Online, - }) - } - } - var authMeths []types.UserAuthMethod - authMethods, err := l.svcCtx.UserModel.FindUserAuthMethods(l.ctx, u.Id) - if err == nil && len(authMeths) != 0 { - for _, as := range authMethods { - authMeths = append(authMeths, types.UserAuthMethod{ - AuthType: as.AuthType, - AuthIdentifier: as.AuthIdentifier, - }) - } - } - - resp = &types.UserInfoResponse{ - Id: u.Id, - Balance: u.Balance, - Avatar: u.Avatar, - ReferCode: u.ReferCode, - RefererId: u.RefererId, - Devices: devices, - AuthMethods: authMeths, - } - return -} diff --git a/internal/logic/app/user/queryuseraffiliatelogic.go b/internal/logic/app/user/queryuseraffiliatelogic.go deleted file mode 100644 index 48d7bc6..0000000 --- a/internal/logic/app/user/queryuseraffiliatelogic.go +++ /dev/null @@ -1,60 +0,0 @@ -package user - -import ( - "context" - - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/pkg/constant" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - "gorm.io/gorm" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" -) - -type QueryUserAffiliateLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Query User Affiliate Count -func NewQueryUserAffiliateLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryUserAffiliateLogic { - return &QueryUserAffiliateLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *QueryUserAffiliateLogic) QueryUserAffiliate() (resp *types.QueryUserAffiliateCountResponse, err error) { - u, ok := l.ctx.Value(constant.CtxKeyUser).(*user.User) - if !ok { - logger.Error("current user is not found in context") - return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access") - } - var sum int64 - var total int64 - err = l.svcCtx.UserModel.Transaction(l.ctx, func(db *gorm.DB) error { - return db.Model(&user.User{}).Where("referer_id = ?", u.Id).Count(&total).Find(&user.User{}).Error - }) - if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Query User Affiliate failed: %v", err) - } - err = l.svcCtx.UserModel.Transaction(l.ctx, func(db *gorm.DB) error { - return db.Model(&user.CommissionLog{}). - Where("user_id = ?", u.Id). - Select("COALESCE(SUM(amount), 0)"). - Scan(&sum).Error - }) - if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Query User Affiliate failed: %v", err) - } - - return &types.QueryUserAffiliateCountResponse{ - Registers: total, - TotalCommission: sum, - }, nil -} diff --git a/internal/logic/app/user/updatePasswordLogic.go b/internal/logic/app/user/updatePasswordLogic.go deleted file mode 100644 index 4dee24d..0000000 --- a/internal/logic/app/user/updatePasswordLogic.go +++ /dev/null @@ -1,46 +0,0 @@ -package user - -import ( - "context" - - "github.com/perfect-panel/server/pkg/constant" - - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type UpdatePasswordLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Update Password -func NewUpdatePasswordLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdatePasswordLogic { - return &UpdatePasswordLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *UpdatePasswordLogic) UpdatePassword(req *types.UpdatePasswordRequeset) error { - userInfo := l.ctx.Value(constant.CtxKeyUser).(*user.User) - - // Verify password - if !tool.VerifyPassWord(req.Password, userInfo.Password) { - return errors.Wrapf(xerr.NewErrCode(xerr.UserPasswordError), "user password") - } - userInfo.Password = tool.EncodePassWord(req.NewPassword) - err := l.svcCtx.UserModel.Update(l.ctx, userInfo) - if err != nil { - l.Errorw("update user password error", logger.Field("error", err.Error())) - return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "update user password") - } - return err -} diff --git a/internal/logic/app/ws/appWsLogic.go b/internal/logic/app/ws/appWsLogic.go deleted file mode 100644 index d86de91..0000000 --- a/internal/logic/app/ws/appWsLogic.go +++ /dev/null @@ -1,81 +0,0 @@ -package ws - -import ( - "context" - "net/http" - "strconv" - "time" - - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/pkg/constant" - "github.com/perfect-panel/server/pkg/xerr" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/logger" -) - -type AppWsLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// App heartbeat -func NewAppWsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AppWsLogic { - return &AppWsLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *AppWsLogic) AppWs(w http.ResponseWriter, r *http.Request, userid, identifier string) error { - //获取设备号 - if identifier == "" { - return xerr.NewErrCode(xerr.DeviceNotExist) - } - //获取用户id - userID, err := strconv.ParseInt(userid, 10, 64) - if err != nil { - return xerr.NewErrCode(xerr.UseridNotMatch) - } - - ////获取session - value := l.ctx.Value(constant.CtxKeySessionID) - if value == nil { - return xerr.NewErrCode(xerr.ErrorTokenInvalid) - } - session := value.(string) - - //获取用户 - userInfo := l.ctx.Value(constant.CtxKeyUser).(*user.User) - - if userID != userInfo.Id { - return xerr.NewErrCode(xerr.UseridNotMatch) - } - - _, err = l.svcCtx.UserModel.FindOneDeviceByIdentifier(l.ctx, identifier) - if err != nil { - return xerr.NewErrCode(xerr.DeviceNotExist) - } - - //if device.UserId != userInfo.Id { - // return xerr.NewErrCode(xerr.DeviceNotExist) - //} - - //默认在线设备1 - maxDevice := 0 - subscribe, err := l.svcCtx.UserModel.QueryUserSubscribe(l.ctx, userInfo.Id) - if err == nil { - for _, sub := range subscribe { - if time.Now().Before(sub.ExpireTime) { - deviceLimit := int(sub.Subscribe.DeviceLimit) - if deviceLimit > maxDevice { - maxDevice = deviceLimit - } - } - } - } - l.svcCtx.DeviceManager.AddDevice(w, r, session, userID, identifier, maxDevice) - return nil -} diff --git a/internal/logic/auth/oauth/oAuthLoginGetTokenLogic.go b/internal/logic/auth/oauth/oAuthLoginGetTokenLogic.go index f3ca443..e84bc30 100644 --- a/internal/logic/auth/oauth/oAuthLoginGetTokenLogic.go +++ b/internal/logic/auth/oauth/oAuthLoginGetTokenLogic.go @@ -8,6 +8,7 @@ import ( "github.com/perfect-panel/server/internal/config" "github.com/perfect-panel/server/internal/model/auth" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/internal/model/user" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" @@ -52,7 +53,6 @@ func NewOAuthLoginGetTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) } func (l *OAuthLoginGetTokenLogic) OAuthLoginGetToken(req *types.OAuthLoginGetTokenRequest, ip, userAgent string) (resp *types.LoginResponse, err error) { - startTime := time.Now() requestID := uuidx.NewUUID().String() loginStatus := false var userInfo *user.User @@ -65,27 +65,10 @@ func (l *OAuthLoginGetTokenLogic) OAuthLoginGetToken(req *types.OAuthLoginGetTok ) defer func() { - duration := time.Since(startTime) - l.recordLoginStatus(&loginStatus, &userInfo, ip, userAgent, requestID) - - if loginStatus { - l.Infow("oauth login completed successfully", - logger.Field("request_id", requestID), - logger.Field("method", req.Method), - logger.Field("user_id", userInfo.Id), - logger.Field("duration_ms", duration.Milliseconds()), - ) - } else { - l.Errorw("oauth login failed", - logger.Field("request_id", requestID), - logger.Field("method", req.Method), - logger.Field("error", err), - logger.Field("duration_ms", duration.Milliseconds()), - ) - } + l.recordLoginStatus(loginStatus, userInfo, ip, userAgent, requestID, req.Method) }() - userInfo, err = l.handleOAuthProvider(req, requestID) + userInfo, err = l.handleOAuthProvider(req, requestID, ip, userAgent) if err != nil { return nil, err } @@ -99,7 +82,7 @@ func (l *OAuthLoginGetTokenLogic) OAuthLoginGetToken(req *types.OAuthLoginGetTok return &types.LoginResponse{Token: token}, nil } -func (l *OAuthLoginGetTokenLogic) google(req *types.OAuthLoginGetTokenRequest, requestID string) (*user.User, error) { +func (l *OAuthLoginGetTokenLogic) google(req *types.OAuthLoginGetTokenRequest, requestID, ip, userAgent string) (*user.User, error) { startTime := time.Now() l.Infow("google oauth processing started", logger.Field("request_id", requestID), @@ -174,10 +157,10 @@ func (l *OAuthLoginGetTokenLogic) google(req *types.OAuthLoginGetTokenRequest, r logger.Field("duration_ms", time.Since(startTime).Milliseconds()), ) - return l.findOrRegisterUser(OAuthGoogle, googleUserInfo.OpenID, googleUserInfo.Email, googleUserInfo.Picture, requestID) + return l.findOrRegisterUser(OAuthGoogle, googleUserInfo.OpenID, googleUserInfo.Email, googleUserInfo.Picture, requestID, ip, userAgent) } -func (l *OAuthLoginGetTokenLogic) apple(req *types.OAuthLoginGetTokenRequest, requestID string) (*user.User, error) { +func (l *OAuthLoginGetTokenLogic) apple(req *types.OAuthLoginGetTokenRequest, requestID, ip, userAgent string) (*user.User, error) { startTime := time.Now() l.Infow("apple oauth processing started", logger.Field("request_id", requestID), @@ -274,10 +257,10 @@ func (l *OAuthLoginGetTokenLogic) apple(req *types.OAuthLoginGetTokenRequest, re logger.Field("duration_ms", time.Since(startTime).Milliseconds()), ) - return l.findOrRegisterUser(OAuthApple, appleUnique, email, "", requestID) + return l.findOrRegisterUser(OAuthApple, appleUnique, email, "", requestID, ip, userAgent) } -func (l *OAuthLoginGetTokenLogic) telegram(req *types.OAuthLoginGetTokenRequest, requestID string) (*user.User, error) { +func (l *OAuthLoginGetTokenLogic) telegram(req *types.OAuthLoginGetTokenRequest, requestID, ip, userAgent string) (*user.User, error) { startTime := time.Now() l.Infow("telegram oauth processing started", logger.Field("request_id", requestID), @@ -337,10 +320,10 @@ func (l *OAuthLoginGetTokenLogic) telegram(req *types.OAuthLoginGetTokenRequest, logger.Field("duration_ms", time.Since(startTime).Milliseconds()), ) - return l.findOrRegisterUser(OAuthTelegram, userID, email, avatar, requestID) + return l.findOrRegisterUser(OAuthTelegram, userID, email, avatar, requestID, ip, userAgent) } -func (l *OAuthLoginGetTokenLogic) register(email, avatar, method, openid, requestID string) (*user.User, error) { +func (l *OAuthLoginGetTokenLogic) register(email, avatar, method, openid, requestID, ip, userAgent string) (*user.User, error) { startTime := time.Now() l.Infow("user registration started", logger.Field("request_id", requestID), @@ -441,6 +424,31 @@ func (l *OAuthLoginGetTokenLogic) register(email, avatar, method, openid, reques logger.Field("duration_ms", time.Since(startTime).Milliseconds()), ) + // Register log + registerLog := log.Register{ + AuthMethod: method, + Identifier: openid, + RegisterIP: ip, + UserAgent: userAgent, + Timestamp: time.Now().UnixMilli(), + } + content, _ := registerLog.Marshal() + + err = l.svcCtx.LogModel.Insert(l.ctx, &log.SystemLog{ + Type: log.TypeRegister.Uint8(), + Date: time.Now().Format("2006-01-02"), + ObjectID: userInfo.Id, + Content: string(content), + }) + if err != nil { + l.Errorw("failed to insert register log", + logger.Field("request_id", requestID), + logger.Field("user_id", userInfo.Id), + logger.Field("ip", ip), + logger.Field("error", err.Error()), + ) + } + return userInfo, err } @@ -504,32 +512,34 @@ func (l *OAuthLoginGetTokenLogic) createAuthMethod(db *gorm.DB, userID int64, au return nil } -func (l *OAuthLoginGetTokenLogic) recordLoginStatus(loginStatus *bool, userInfo **user.User, ip, userAgent, requestID string) { - if *userInfo != nil && (*userInfo).Id != 0 { - if err := l.svcCtx.UserModel.InsertLoginLog(l.ctx, &user.LoginLog{ - UserId: (*userInfo).Id, +func (l *OAuthLoginGetTokenLogic) recordLoginStatus(loginStatus bool, userInfo *user.User, ip, userAgent, requestID, authType string) { + + if userInfo != nil && userInfo.Id != 0 { + loginLog := log.Login{ + Method: authType, LoginIP: ip, UserAgent: userAgent, Success: loginStatus, + Timestamp: time.Now().UnixMilli(), + } + content, _ := loginLog.Marshal() + if err := l.svcCtx.LogModel.Insert(l.ctx, &log.SystemLog{ + Type: log.TypeLogin.Uint8(), + Date: time.Now().Format("2006-01-02"), + ObjectID: userInfo.Id, + Content: string(content), }); err != nil { l.Errorw("failed to insert login log", logger.Field("request_id", requestID), - logger.Field("user_id", (*userInfo).Id), + logger.Field("user_id", userInfo.Id), logger.Field("ip", ip), logger.Field("error", err.Error()), ) - } else { - l.Debugw("login log recorded successfully", - logger.Field("request_id", requestID), - logger.Field("user_id", (*userInfo).Id), - logger.Field("ip", ip), - logger.Field("success", *loginStatus), - ) } } } -func (l *OAuthLoginGetTokenLogic) handleOAuthProvider(req *types.OAuthLoginGetTokenRequest, requestID string) (*user.User, error) { +func (l *OAuthLoginGetTokenLogic) handleOAuthProvider(req *types.OAuthLoginGetTokenRequest, requestID, ip, userAgent string) (*user.User, error) { l.Debugw("handling oauth provider", logger.Field("request_id", requestID), logger.Field("provider", req.Method), @@ -537,11 +547,11 @@ func (l *OAuthLoginGetTokenLogic) handleOAuthProvider(req *types.OAuthLoginGetTo switch req.Method { case OAuthGoogle: - return l.google(req, requestID) + return l.google(req, requestID, ip, userAgent) case OAuthApple: - return l.apple(req, requestID) + return l.apple(req, requestID, ip, userAgent) case OAuthTelegram: - return l.telegram(req, requestID) + return l.telegram(req, requestID, ip, userAgent) default: l.Errorw("unsupported oauth login method", logger.Field("request_id", requestID), @@ -730,7 +740,7 @@ func (l *OAuthLoginGetTokenLogic) getTelegramConfig(requestID string) (*auth.Tel return &cfg, nil } -func (l *OAuthLoginGetTokenLogic) findOrRegisterUser(authType, openID, email, avatar, requestID string) (*user.User, error) { +func (l *OAuthLoginGetTokenLogic) findOrRegisterUser(authType, openID, email, avatar, requestID, ip, userAgent string) (*user.User, error) { l.Debugw("finding or registering user", logger.Field("request_id", requestID), logger.Field("auth_type", authType), @@ -747,7 +757,7 @@ func (l *OAuthLoginGetTokenLogic) findOrRegisterUser(authType, openID, email, av logger.Field("openid", openID), logger.Field("email", email), ) - return l.register(email, avatar, authType, openID, requestID) + return l.register(email, avatar, authType, openID, requestID, ip, userAgent) } l.Errorw("failed to find user auth method by openid", logger.Field("request_id", requestID), diff --git a/internal/logic/auth/resetPasswordLogic.go b/internal/logic/auth/resetPasswordLogic.go index b489606..d0d3f2f 100644 --- a/internal/logic/auth/resetPasswordLogic.go +++ b/internal/logic/auth/resetPasswordLogic.go @@ -6,6 +6,7 @@ import ( "fmt" "time" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/internal/model/user" "github.com/perfect-panel/server/pkg/jwt" "github.com/perfect-panel/server/pkg/uuidx" @@ -43,13 +44,26 @@ func (l *ResetPasswordLogic) ResetPassword(req *types.ResetPasswordRequest) (res defer func() { if userInfo.Id != 0 && loginStatus { - if err := l.svcCtx.UserModel.InsertLoginLog(l.ctx, &user.LoginLog{ - UserId: userInfo.Id, + loginLog := log.Login{ + Method: "email", LoginIP: req.IP, UserAgent: req.UserAgent, - Success: &loginStatus, + Success: loginStatus, + Timestamp: time.Now().UnixMilli(), + } + content, _ := loginLog.Marshal() + if err := l.svcCtx.LogModel.Insert(l.ctx, &log.SystemLog{ + Id: 0, + Type: log.TypeLogin.Uint8(), + Date: time.Now().Format("2006-01-02"), + ObjectID: userInfo.Id, + Content: string(content), }); err != nil { - l.Logger.Error("[ResetPassword] insert login log error", logger.Field("error", err.Error())) + l.Errorw("failed to insert login log", + logger.Field("user_id", userInfo.Id), + logger.Field("ip", req.IP), + logger.Field("error", err.Error()), + ) } } }() diff --git a/internal/logic/auth/telephoneLoginLogic.go b/internal/logic/auth/telephoneLoginLogic.go index 5457b39..54e4d8e 100644 --- a/internal/logic/auth/telephoneLoginLogic.go +++ b/internal/logic/auth/telephoneLoginLogic.go @@ -9,6 +9,7 @@ import ( "github.com/perfect-panel/server/internal/config" "github.com/perfect-panel/server/internal/logic/common" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/internal/model/user" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" @@ -51,13 +52,26 @@ func (l *TelephoneLoginLogic) TelephoneLogin(req *types.TelephoneLoginRequest, r // Record login status defer func(svcCtx *svc.ServiceContext) { if userInfo.Id != 0 { - if err := svcCtx.UserModel.InsertLoginLog(l.ctx, &user.LoginLog{ - UserId: userInfo.Id, + loginLog := log.Login{ + Method: "mobile", LoginIP: ip, UserAgent: r.UserAgent(), - Success: &loginStatus, + Success: loginStatus, + Timestamp: time.Now().UnixMilli(), + } + content, _ := loginLog.Marshal() + if err := l.svcCtx.LogModel.Insert(l.ctx, &log.SystemLog{ + Id: 0, + Type: log.TypeLogin.Uint8(), + Date: time.Now().Format("2006-01-02"), + ObjectID: userInfo.Id, + Content: string(content), }); err != nil { - l.Logger.Error("[UserLogin] insert login log error", logger.Field("error", err.Error())) + l.Errorw("failed to insert login log", + logger.Field("user_id", userInfo.Id), + logger.Field("ip", req.IP), + logger.Field("error", err.Error()), + ) } } }(l.svcCtx) diff --git a/internal/logic/auth/telephoneResetPasswordLogic.go b/internal/logic/auth/telephoneResetPasswordLogic.go index 972b9ae..18891b0 100644 --- a/internal/logic/auth/telephoneResetPasswordLogic.go +++ b/internal/logic/auth/telephoneResetPasswordLogic.go @@ -6,6 +6,7 @@ import ( "time" "github.com/perfect-panel/server/internal/config" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/constant" @@ -100,6 +101,31 @@ func (l *TelephoneResetPasswordLogic) TelephoneResetPassword(req *types.Telephon if err = l.svcCtx.Redis.Set(l.ctx, sessionIdCacheKey, userInfo.Id, time.Duration(l.svcCtx.Config.JwtAuth.AccessExpire)*time.Second).Err(); err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "set session id error: %v", err.Error()) } + defer func() { + if token != "" && userInfo.Id != 0 { + loginLog := log.Login{ + Method: "mobile", + LoginIP: req.IP, + UserAgent: req.UserAgent, + Success: token != "", + Timestamp: time.Now().UnixMilli(), + } + content, _ := loginLog.Marshal() + if err := l.svcCtx.LogModel.Insert(l.ctx, &log.SystemLog{ + Id: 0, + Type: log.TypeLogin.Uint8(), + Date: time.Now().Format("2006-01-02"), + ObjectID: userInfo.Id, + Content: string(content), + }); err != nil { + l.Errorw("failed to insert login log", + logger.Field("user_id", userInfo.Id), + logger.Field("ip", req.IP), + logger.Field("error", err.Error()), + ) + } + } + }() return &types.LoginResponse{ Token: token, }, nil diff --git a/internal/logic/auth/telephoneUserRegisterLogic.go b/internal/logic/auth/telephoneUserRegisterLogic.go index 0ff2c6d..e29f3fa 100644 --- a/internal/logic/auth/telephoneUserRegisterLogic.go +++ b/internal/logic/auth/telephoneUserRegisterLogic.go @@ -6,6 +6,7 @@ import ( "fmt" "time" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/pkg/constant" "github.com/perfect-panel/server/internal/config" @@ -154,6 +155,53 @@ func (l *TelephoneUserRegisterLogic) TelephoneUserRegister(req *types.TelephoneR if err = l.svcCtx.Redis.Set(l.ctx, sessionIdCacheKey, userInfo.Id, time.Duration(l.svcCtx.Config.JwtAuth.AccessExpire)*time.Second).Err(); err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "set session id error: %v", err.Error()) } + + defer func() { + if token != "" && userInfo.Id != 0 { + loginLog := log.Login{ + Method: "mobile", + LoginIP: req.IP, + UserAgent: req.UserAgent, + Success: token != "", + Timestamp: time.Now().UnixMilli(), + } + content, _ := loginLog.Marshal() + if err := l.svcCtx.LogModel.Insert(l.ctx, &log.SystemLog{ + Id: 0, + Type: log.TypeLogin.Uint8(), + Date: time.Now().Format("2006-01-02"), + ObjectID: userInfo.Id, + Content: string(content), + }); err != nil { + l.Errorw("failed to insert login log", + logger.Field("user_id", userInfo.Id), + logger.Field("ip", req.IP), + logger.Field("error", err.Error()), + ) + } + + // Register log + registerLog := log.Register{ + AuthMethod: "mobile", + Identifier: phoneNumber, + RegisterIP: req.IP, + UserAgent: req.UserAgent, + Timestamp: time.Now().UnixMilli(), + } + content, _ = registerLog.Marshal() + if err := l.svcCtx.LogModel.Insert(l.ctx, &log.SystemLog{ + Type: log.TypeRegister.Uint8(), + ObjectID: userInfo.Id, + Date: time.Now().Format("2006-01-02"), + Content: string(content), + }); err != nil { + l.Errorw("failed to insert login log", + logger.Field("user_id", userInfo.Id), + logger.Field("ip", req.IP), + logger.Field("error", err.Error())) + } + } + }() return &types.LoginResponse{ Token: token, }, nil diff --git a/internal/logic/auth/userLoginLogic.go b/internal/logic/auth/userLoginLogic.go index c04392c..d328924 100644 --- a/internal/logic/auth/userLoginLogic.go +++ b/internal/logic/auth/userLoginLogic.go @@ -5,6 +5,7 @@ import ( "fmt" "time" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/pkg/logger" "github.com/perfect-panel/server/internal/config" @@ -41,25 +42,39 @@ func (l *UserLoginLogic) UserLogin(req *types.UserLoginRequest) (resp *types.Log // Record login status defer func(svcCtx *svc.ServiceContext) { if userInfo.Id != 0 { - if err := svcCtx.UserModel.InsertLoginLog(l.ctx, &user.LoginLog{ - UserId: userInfo.Id, + loginLog := log.Login{ + Method: "email", LoginIP: req.IP, UserAgent: req.UserAgent, - Success: &loginStatus, + Success: loginStatus, + Timestamp: time.Now().UnixMilli(), + } + content, _ := loginLog.Marshal() + if err := l.svcCtx.LogModel.Insert(l.ctx, &log.SystemLog{ + Type: log.TypeLogin.Uint8(), + Date: time.Now().Format("2006-01-02"), + ObjectID: userInfo.Id, + Content: string(content), }); err != nil { - l.Logger.Error("[UserLogin] insert login log error", logger.Field("error", err.Error())) + l.Errorw("failed to insert login log", + logger.Field("user_id", userInfo.Id), + logger.Field("ip", req.IP), + logger.Field("error", err.Error()), + ) } } }(l.svcCtx) userInfo, err = l.svcCtx.UserModel.FindOneByEmail(l.ctx, req.Email) + if err != nil { if errors.As(err, &gorm.ErrRecordNotFound) { - logger.WithContext(l.ctx).Error(err) return nil, errors.Wrapf(xerr.NewErrCode(xerr.UserNotExist), "user email not exist: %v", req.Email) } + logger.WithContext(l.ctx).Error(err) return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query user info failed: %v", err.Error()) } + // Verify password if !tool.VerifyPassWord(req.Password, userInfo.Password) { return nil, errors.Wrapf(xerr.NewErrCode(xerr.UserPasswordError), "user password") diff --git a/internal/logic/auth/userRegisterLogic.go b/internal/logic/auth/userRegisterLogic.go index 19c2282..221cee6 100644 --- a/internal/logic/auth/userRegisterLogic.go +++ b/internal/logic/auth/userRegisterLogic.go @@ -8,6 +8,7 @@ import ( "github.com/perfect-panel/server/internal/config" "github.com/perfect-panel/server/internal/logic/common" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/internal/model/user" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" @@ -145,13 +146,47 @@ func (l *UserRegisterLogic) UserRegister(req *types.UserRegisterRequest) (resp * loginStatus := true defer func() { if token != "" && userInfo.Id != 0 { - if err := l.svcCtx.UserModel.InsertLoginLog(l.ctx, &user.LoginLog{ - UserId: userInfo.Id, + loginLog := log.Login{ + Method: "email", LoginIP: req.IP, UserAgent: req.UserAgent, - Success: &loginStatus, + Success: loginStatus, + Timestamp: time.Now().UnixMilli(), + } + content, _ := loginLog.Marshal() + if err := l.svcCtx.LogModel.Insert(l.ctx, &log.SystemLog{ + Id: 0, + Type: log.TypeLogin.Uint8(), + Date: time.Now().Format("2006-01-02"), + ObjectID: userInfo.Id, + Content: string(content), }); err != nil { - l.Logger.Error("[UserRegister] insert login log error", logger.Field("error", err.Error())) + l.Errorw("failed to insert login log", + logger.Field("user_id", userInfo.Id), + logger.Field("ip", req.IP), + logger.Field("error", err.Error()), + ) + } + + // Register log + registerLog := log.Register{ + AuthMethod: "email", + Identifier: req.Email, + RegisterIP: req.IP, + UserAgent: req.UserAgent, + Timestamp: time.Now().UnixMilli(), + } + content, _ = registerLog.Marshal() + if err = l.svcCtx.LogModel.Insert(l.ctx, &log.SystemLog{ + Type: log.TypeRegister.Uint8(), + ObjectID: userInfo.Id, + Date: time.Now().Format("2006-01-02"), + Content: string(content), + }); err != nil { + l.Errorw("failed to insert login log", + logger.Field("user_id", userInfo.Id), + logger.Field("ip", req.IP), + logger.Field("error", err.Error())) } } }() diff --git a/internal/logic/common/getApplicationLogic.go b/internal/logic/common/getApplicationLogic.go deleted file mode 100644 index 7a4b6d6..0000000 --- a/internal/logic/common/getApplicationLogic.go +++ /dev/null @@ -1,136 +0,0 @@ -package common - -import ( - "context" - "strings" - - "github.com/perfect-panel/server/internal/model/application" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - "gorm.io/gorm" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" -) - -type GetApplicationLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Get Tos Content -func NewGetApplicationLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetApplicationLogic { - return &GetApplicationLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *GetApplicationLogic) GetApplication() (resp *types.GetAppcationResponse, err error) { - resp = &types.GetAppcationResponse{} - - cfg, err := l.svcCtx.ApplicationModel.FindOneConfig(l.ctx, 1) - if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - l.Logger.Error("[GetAppInfo] FindOneAppConfig error: ", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "GetAppInfo FindOneAppConfig error: %v", err.Error()) - } - if err != nil { - resp.Config = types.ApplicationConfig{} - } else { - resp.Config = types.ApplicationConfig{ - AppId: cfg.AppId, - EncryptionKey: cfg.EncryptionKey, - EncryptionMethod: cfg.EncryptionMethod, - Domains: strings.Split(cfg.Domains, ";"), - StartupPicture: cfg.StartupPicture, - StartupPictureSkipTime: cfg.StartupPictureSkipTime, - } - } - - var applications []*application.Application - err = l.svcCtx.ApplicationModel.Transaction(l.ctx, func(tx *gorm.DB) (err error) { - return tx.Model(applications).Preload("ApplicationVersions").Find(&applications).Error - }) - if err != nil { - l.Errorw("[QueryApplicationConfig] get application error: ", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "get application error: %v", err.Error()) - } - - if len(applications) == 0 { - return resp, nil - } - - for _, app := range applications { - applicationResponse := types.ApplicationResponseInfo{ - Id: app.Id, - Name: app.Name, - Icon: app.Icon, - Description: app.Description, - SubscribeType: app.SubscribeType, - } - applicationVersions := app.ApplicationVersions - if len(applicationVersions) != 0 { - for _, applicationVersion := range applicationVersions { - /*if !applicationVersion.IsDefault { - continue - }*/ - switch applicationVersion.Platform { - case "ios": - applicationResponse.Platform.IOS = append(applicationResponse.Platform.IOS, &types.ApplicationVersion{ - Id: applicationVersion.Id, - Url: applicationVersion.Url, - Version: applicationVersion.Version, - IsDefault: applicationVersion.IsDefault, - Description: applicationVersion.Description, - }) - case "macos": - applicationResponse.Platform.MacOS = append(applicationResponse.Platform.MacOS, &types.ApplicationVersion{ - Id: applicationVersion.Id, - Url: applicationVersion.Url, - Version: applicationVersion.Version, - IsDefault: applicationVersion.IsDefault, - Description: applicationVersion.Description, - }) - case "linux": - applicationResponse.Platform.Linux = append(applicationResponse.Platform.Linux, &types.ApplicationVersion{ - Id: applicationVersion.Id, - Url: applicationVersion.Url, - Version: applicationVersion.Version, - IsDefault: applicationVersion.IsDefault, - Description: applicationVersion.Description, - }) - case "android": - applicationResponse.Platform.Android = append(applicationResponse.Platform.Android, &types.ApplicationVersion{ - Id: applicationVersion.Id, - Url: applicationVersion.Url, - Version: applicationVersion.Version, - IsDefault: applicationVersion.IsDefault, - Description: applicationVersion.Description, - }) - case "windows": - applicationResponse.Platform.Windows = append(applicationResponse.Platform.Windows, &types.ApplicationVersion{ - Id: applicationVersion.Id, - Url: applicationVersion.Url, - Version: applicationVersion.Version, - IsDefault: applicationVersion.IsDefault, - Description: applicationVersion.Description, - }) - case "harmony": - applicationResponse.Platform.Harmony = append(applicationResponse.Platform.Harmony, &types.ApplicationVersion{ - Id: applicationVersion.Id, - Url: applicationVersion.Url, - Version: applicationVersion.Version, - IsDefault: applicationVersion.IsDefault, - Description: applicationVersion.Description, - }) - } - } - } - resp.Applications = append(resp.Applications, applicationResponse) - } - - return -} diff --git a/internal/logic/common/getSubscriptionLogic.go b/internal/logic/common/getSubscriptionLogic.go deleted file mode 100644 index 463abfe..0000000 --- a/internal/logic/common/getSubscriptionLogic.go +++ /dev/null @@ -1,41 +0,0 @@ -package common - -import ( - "context" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -type GetSubscriptionLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Get Subscription -func NewGetSubscriptionLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetSubscriptionLogic { - return &GetSubscriptionLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *GetSubscriptionLogic) GetSubscription() (resp *types.GetSubscriptionResponse, err error) { - resp = &types.GetSubscriptionResponse{ - List: make([]types.Subscribe, 0), - } - // Get the subscription list - data, err := l.svcCtx.SubscribeModel.QuerySubscribeListByShow(l.ctx) - if err != nil { - l.Errorw("[Site GetSubscription]", logger.Field("err", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "get subscription list error: %v", err.Error()) - } - tool.DeepCopy(&resp.List, data) - return -} diff --git a/internal/logic/common/sendEmailCodeLogic.go b/internal/logic/common/sendEmailCodeLogic.go index ac37acc..c538d72 100644 --- a/internal/logic/common/sendEmailCodeLogic.go +++ b/internal/logic/common/sendEmailCodeLogic.go @@ -1,11 +1,9 @@ package common import ( - "bytes" "context" "encoding/json" "fmt" - "text/template" "time" "github.com/hibiken/asynq" @@ -88,14 +86,16 @@ func (l *SendEmailCodeLogic) SendEmailCode(req *types.SendCodeRequest) (resp *ty var taskPayload queue.SendEmailPayload // Generate verification code code := random.Key(6, 0) + taskPayload.Type = queue.EmailTypeVerify taskPayload.Email = req.Email taskPayload.Subject = "Verification code" - content, err := l.initTemplate(req.Type, code) - if err != nil { - l.Logger.Error("[SendEmailCode]: InitTemplate Error", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "Failed to init template") + taskPayload.Content = map[string]interface{}{ + "Type": req.Type, + "SiteLogo": l.svcCtx.Config.Site.SiteLogo, + "SiteName": l.svcCtx.Config.Site.SiteName, + "Expire": 5, + "Code": code, } - taskPayload.Content = content // Save to Redis payload = CacheKeyPayload{ Code: code, @@ -134,23 +134,3 @@ func (l *SendEmailCodeLogic) SendEmailCode(req *types.SendCodeRequest) (resp *ty }, nil } } - -func (l *SendEmailCodeLogic) initTemplate(t uint8, code string) (string, error) { - data := VerifyTemplate{ - Type: t, - SiteLogo: l.svcCtx.Config.Site.SiteLogo, - SiteName: l.svcCtx.Config.Site.SiteName, - Expire: 5, - Code: code, - } - tpl, err := template.New("verify").Parse(l.svcCtx.Config.Email.VerifyEmailTemplate) - if err != nil { - return "", err - } - var result bytes.Buffer - err = tpl.Execute(&result, data) - if err != nil { - return "", err - } - return result.String(), nil -} diff --git a/internal/logic/public/order/closeOrderLogic.go b/internal/logic/public/order/closeOrderLogic.go index fc22eec..ced53b8 100644 --- a/internal/logic/public/order/closeOrderLogic.go +++ b/internal/logic/public/order/closeOrderLogic.go @@ -3,7 +3,9 @@ package order import ( "context" "encoding/json" + "time" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/internal/model/user" "github.com/perfect-panel/server/pkg/payment/stripe" "gorm.io/gorm" @@ -92,15 +94,25 @@ func (l *CloseOrderLogic) CloseOrder(req *types.CloseOrderRequest) error { return err } // Record the deduction refund log - giftAmountLog := &user.GiftAmountLog{ - UserId: orderInfo.UserId, - OrderNo: orderInfo.OrderNo, - Amount: orderInfo.GiftAmount, - Type: 1, - Balance: deduction, - Remark: "Order cancellation refund", + + giftLog := log.Gift{ + Type: log.GiftTypeIncrease, + OrderNo: orderInfo.OrderNo, + SubscribeId: 0, + Amount: orderInfo.GiftAmount, + Balance: deduction, + Remark: "Order cancellation refund", + Timestamp: time.Now().UnixMilli(), } - err = tx.Model(&user.GiftAmountLog{}).Create(giftAmountLog).Error + content, _ := giftLog.Marshal() + + err = tx.Model(&log.SystemLog{}).Create(&log.SystemLog{ + Id: 0, + Type: log.TypeGift.Uint8(), + Date: time.Now().Format(time.DateOnly), + ObjectID: userInfo.Id, + Content: string(content), + }).Error if err != nil { l.Errorw("[CloseOrder] Record cancellation refund log failed", logger.Field("error", err.Error()), diff --git a/internal/logic/public/order/purchaseLogic.go b/internal/logic/public/order/purchaseLogic.go index 033ad9a..94dbb16 100644 --- a/internal/logic/public/order/purchaseLogic.go +++ b/internal/logic/public/order/purchaseLogic.go @@ -5,6 +5,7 @@ import ( "encoding/json" "time" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/pkg/constant" "github.com/hibiken/asynq" @@ -196,18 +197,26 @@ func (l *PurchaseLogic) Purchase(req *types.PurchaseOrderRequest) (resp *types.P return e } // create deduction record - giftAmountLog := user.GiftAmountLog{ - UserId: orderInfo.UserId, - OrderNo: orderInfo.OrderNo, - Amount: orderInfo.GiftAmount, - Type: 2, - Balance: u.GiftAmount, - Remark: "Purchase order deduction", + giftLog := log.Gift{ + Type: log.GiftTypeReduce, + OrderNo: orderInfo.OrderNo, + SubscribeId: 0, + Amount: orderInfo.GiftAmount, + Balance: u.GiftAmount, + Remark: "Purchase order deduction", + Timestamp: time.Now().UnixMilli(), } - if e := db.Model(&user.GiftAmountLog{}).Create(&giftAmountLog).Error; e != nil { + content, _ := giftLog.Marshal() + + if e := db.Model(&log.SystemLog{}).Create(&log.SystemLog{ + Type: log.TypeGift.Uint8(), + Date: time.Now().Format(time.DateOnly), + ObjectID: u.Id, + Content: string(content), + }).Error; e != nil { l.Errorw("[Purchase] Database insert error", logger.Field("error", e.Error()), - logger.Field("deductionLog", giftAmountLog), + logger.Field("deductionLog", giftLog), ) return e } diff --git a/internal/logic/public/order/renewalLogic.go b/internal/logic/public/order/renewalLogic.go index 6692628..5680c9b 100644 --- a/internal/logic/public/order/renewalLogic.go +++ b/internal/logic/public/order/renewalLogic.go @@ -5,6 +5,7 @@ import ( "encoding/json" "time" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/pkg/constant" "gorm.io/gorm" @@ -163,16 +164,24 @@ func (l *RenewalLogic) Renewal(req *types.RenewalOrderRequest) (resp *types.Rene return err } // create deduction record - deductionLog := user.GiftAmountLog{ - UserId: orderInfo.UserId, - OrderNo: orderInfo.OrderNo, - Amount: orderInfo.GiftAmount, - Type: 2, - Balance: u.GiftAmount, - Remark: "Renewal order deduction", + giftLog := log.Gift{ + Type: log.GiftTypeReduce, + OrderNo: orderInfo.OrderNo, + SubscribeId: 0, + Amount: orderInfo.GiftAmount, + Balance: u.GiftAmount, + Remark: "Renewal order deduction", + Timestamp: time.Now().UnixMilli(), } - if err := db.Model(&user.GiftAmountLog{}).Create(&deductionLog).Error; err != nil { - l.Errorw("[Renewal] Database insert error", logger.Field("error", err.Error()), logger.Field("deductionLog", deductionLog)) + content, _ := giftLog.Marshal() + + if err := db.Model(&log.SystemLog{}).Create(&log.SystemLog{ + Type: log.TypeGift.Uint8(), + Date: time.Now().Format(time.DateOnly), + ObjectID: u.Id, + Content: string(content), + }).Error; err != nil { + l.Errorw("[Renewal] Database insert error", logger.Field("error", err.Error()), logger.Field("deductionLog", giftLog)) return err } } diff --git a/internal/logic/public/order/resetTrafficLogic.go b/internal/logic/public/order/resetTrafficLogic.go index 03ec1a0..1fc9b57 100644 --- a/internal/logic/public/order/resetTrafficLogic.go +++ b/internal/logic/public/order/resetTrafficLogic.go @@ -5,6 +5,7 @@ import ( "encoding/json" "time" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/pkg/constant" "github.com/perfect-panel/server/pkg/xerr" @@ -104,16 +105,24 @@ func (l *ResetTrafficLogic) ResetTraffic(req *types.ResetTrafficOrderRequest) (r return err } // create deduction record - deductionLog := user.GiftAmountLog{ - UserId: orderInfo.UserId, - OrderNo: orderInfo.OrderNo, - Amount: orderInfo.GiftAmount, - Type: 2, - Balance: u.GiftAmount, - Remark: "ResetTraffic order deduction", + giftLog := log.Gift{ + Type: log.GiftTypeReduce, + OrderNo: orderInfo.OrderNo, + SubscribeId: 0, + Amount: orderInfo.GiftAmount, + Balance: u.GiftAmount, + Remark: "Renewal order deduction", + Timestamp: time.Now().UnixMilli(), } - if err := db.Model(&user.GiftAmountLog{}).Create(&deductionLog).Error; err != nil { - l.Errorw("[ResetTraffic] Database insert error", logger.Field("error", err.Error()), logger.Field("deductionLog", deductionLog)) + content, _ := giftLog.Marshal() + + if err = db.Model(&log.SystemLog{}).Create(&log.SystemLog{ + Type: log.TypeGift.Uint8(), + Date: time.Now().Format(time.DateOnly), + ObjectID: u.Id, + Content: string(content), + }).Error; err != nil { + l.Errorw("[ResetTraffic] Database insert error", logger.Field("error", err.Error()), logger.Field("deductionLog", content)) return err } } diff --git a/internal/logic/public/portal/getSubscriptionLogic.go b/internal/logic/public/portal/getSubscriptionLogic.go index 5e85447..51fbaa6 100644 --- a/internal/logic/public/portal/getSubscriptionLogic.go +++ b/internal/logic/public/portal/getSubscriptionLogic.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" + "github.com/perfect-panel/server/internal/model/subscribe" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" @@ -27,12 +28,18 @@ func NewGetSubscriptionLogic(ctx context.Context, svcCtx *svc.ServiceContext) *G } } -func (l *GetSubscriptionLogic) GetSubscription() (resp *types.GetSubscriptionResponse, err error) { +func (l *GetSubscriptionLogic) GetSubscription(req *types.GetSubscriptionRequest) (resp *types.GetSubscriptionResponse, err error) { resp = &types.GetSubscriptionResponse{ List: make([]types.Subscribe, 0), } // Get the subscription list - data, err := l.svcCtx.SubscribeModel.QuerySubscribeListByShow(l.ctx) + _, data, err := l.svcCtx.SubscribeModel.FilterList(l.ctx, &subscribe.FilterParams{ + Page: 1, + Size: 9999, + Show: true, + Language: req.Language, + DefaultLanguage: true, + }) if err != nil { l.Errorw("[Site GetSubscription]", logger.Field("err", err.Error())) return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "get subscription list error: %v", err.Error()) diff --git a/internal/logic/public/portal/purchaseCheckoutLogic.go b/internal/logic/public/portal/purchaseCheckoutLogic.go index 1b71b08..f2efd71 100644 --- a/internal/logic/public/portal/purchaseCheckoutLogic.go +++ b/internal/logic/public/portal/purchaseCheckoutLogic.go @@ -4,7 +4,9 @@ import ( "context" "encoding/json" "strconv" + "time" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/pkg/constant" paymentPlatform "github.com/perfect-panel/server/pkg/payment" @@ -104,6 +106,17 @@ func (l *PurchaseCheckoutLogic) PurchaseCheckout(req *types.CheckoutOrderRequest CheckoutUrl: url, } + case paymentPlatform.CryptoSaaS: + // Process EPay payment - generates payment URL for redirect + url, err := l.epayPayment(paymentConfig, orderInfo, req.ReturnUrl) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "epayPayment error: %v", err.Error()) + } + resp = &types.CheckoutOrderResponse{ + CheckoutUrl: url, + Type: "url", // Client should redirect to URL + } + case paymentPlatform.Balance: // Process balance payment - validate user and process payment immediately if orderInfo.UserId == 0 { @@ -138,8 +151,8 @@ func (l *PurchaseCheckoutLogic) PurchaseCheckout(req *types.CheckoutOrderRequest // It handles currency conversion and creates a pre-payment trade for QR code scanning func (l *PurchaseCheckoutLogic) alipayF2fPayment(pay *payment.Payment, info *order.Order) (string, error) { // Parse Alipay F2F configuration from payment settings - f2FConfig := payment.AlipayF2FConfig{} - if err := json.Unmarshal([]byte(pay.Config), &f2FConfig); err != nil { + f2FConfig := &payment.AlipayF2FConfig{} + if err := f2FConfig.Unmarshal([]byte(pay.Config)); err != nil { l.Errorw("[PurchaseCheckout] Unmarshal Alipay config error", logger.Field("error", err.Error())) return "", errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "Unmarshal error: %s", err.Error()) } @@ -189,8 +202,9 @@ func (l *PurchaseCheckoutLogic) alipayF2fPayment(pay *payment.Payment, info *ord // It supports various payment methods including WeChat Pay and Alipay through Stripe func (l *PurchaseCheckoutLogic) stripePayment(config string, info *order.Order, identifier string) (*types.StripePayment, error) { // Parse Stripe configuration from payment settings - stripeConfig := payment.StripeConfig{} - if err := json.Unmarshal([]byte(config), &stripeConfig); err != nil { + stripeConfig := &payment.StripeConfig{} + + if err := stripeConfig.Unmarshal([]byte(config)); err != nil { l.Errorw("[PurchaseCheckout] Unmarshal Stripe config error", logger.Field("error", err.Error())) return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "Unmarshal error: %s", err.Error()) } @@ -247,12 +261,11 @@ func (l *PurchaseCheckoutLogic) stripePayment(config string, info *order.Order, // It handles currency conversion and creates a payment URL for external payment processing func (l *PurchaseCheckoutLogic) epayPayment(config *payment.Payment, info *order.Order, returnUrl string) (string, error) { // Parse EPay configuration from payment settings - epayConfig := payment.EPayConfig{} - if err := json.Unmarshal([]byte(config.Config), &epayConfig); err != nil { + epayConfig := &payment.EPayConfig{} + if err := epayConfig.Unmarshal([]byte(config.Config)); err != nil { l.Errorw("[PurchaseCheckout] Unmarshal EPay config error", logger.Field("error", err.Error())) return "", errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "Unmarshal error: %s", err.Error()) } - // Initialize EPay client with merchant credentials client := epay.NewClient(epayConfig.Pid, epayConfig.Url, epayConfig.Key) @@ -286,6 +299,48 @@ func (l *PurchaseCheckoutLogic) epayPayment(config *payment.Payment, info *order return url, nil } +// CryptoSaaSPayment processes CryptoSaaSPayment payment by generating a payment URL for redirect +// It handles currency conversion and creates a payment URL for external payment processing +func (l *PurchaseCheckoutLogic) CryptoSaaSPayment(config *payment.Payment, info *order.Order, returnUrl string) (string, error) { + // Parse EPay configuration from payment settings + epayConfig := &payment.CryptoSaaSConfig{} + if err := epayConfig.Unmarshal([]byte(config.Config)); err != nil { + l.Errorw("[PurchaseCheckout] Unmarshal EPay config error", logger.Field("error", err.Error())) + return "", errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "Unmarshal error: %s", err.Error()) + } + // Initialize EPay client with merchant credentials + client := epay.NewClient(epayConfig.AccountID, epayConfig.Endpoint, epayConfig.SecretKey) + + // Convert order amount to CNY using current exchange rate + amount, err := l.queryExchangeRate("CNY", info.Amount) + if err != nil { + return "", err + } + + // Build notification URL for payment status callbacks + notifyUrl := "" + if config.Domain != "" { + notifyUrl = config.Domain + "/v1/notify/" + config.Platform + "/" + config.Token + } else { + host, ok := l.ctx.Value(constant.CtxKeyRequestHost).(string) + if !ok { + host = l.svcCtx.Config.Host + } + notifyUrl = "https://" + host + "/v1/notify/" + config.Platform + "/" + config.Token + } + + // Create payment URL for user redirection + url := client.CreatePayUrl(epay.Order{ + Name: l.svcCtx.Config.Site.SiteName, + Amount: amount, + OrderNo: info.OrderNo, + SignType: "MD5", + NotifyUrl: notifyUrl, + ReturnUrl: returnUrl, + }) + return url, nil +} + // queryExchangeRate converts the order amount from system currency to target currency // It retrieves the current exchange rate and performs currency conversion if needed func (l *PurchaseCheckoutLogic) queryExchangeRate(to string, src int64) (amount float64, err error) { @@ -335,7 +390,7 @@ func (l *PurchaseCheckoutLogic) balancePayment(u *user.User, o *order.Order) err logger.Field("orderNo", o.OrderNo), logger.Field("userId", u.Id), ) - err := l.svcCtx.OrderModel.UpdateOrderStatus(l.ctx, o.OrderNo, 2) + err = l.svcCtx.OrderModel.UpdateOrderStatus(l.ctx, o.OrderNo, 2) if err != nil { l.Errorw("[PurchaseCheckout] Update order status error", logger.Field("error", err.Error()), @@ -386,16 +441,21 @@ func (l *PurchaseCheckoutLogic) balancePayment(u *user.User, o *order.Order) err // Create gift amount log if gift amount was used if giftUsed > 0 { - giftLog := &user.GiftAmountLog{ - UserId: u.Id, - UserSubscribeId: 0, // Will be updated when subscription is created - OrderNo: o.OrderNo, - Type: 2, // Type 2 represents gift amount decrease/usage - Amount: giftUsed, - Balance: userInfo.GiftAmount, - Remark: "Purchase payment", + giftLog := &log.Gift{ + OrderNo: o.OrderNo, + Type: log.GiftTypeReduce, // Type 2 represents gift amount decrease/usage + Amount: giftUsed, + Balance: userInfo.GiftAmount, + Remark: "Purchase payment", } - err = db.Create(giftLog).Error + content, _ := giftLog.Marshal() + + err = db.Create(&log.SystemLog{ + Type: log.TypeGift.Uint8(), + ObjectID: userInfo.Id, + Date: time.Now().Format(time.DateOnly), + Content: string(content), + }).Error if err != nil { return err } @@ -403,14 +463,20 @@ func (l *PurchaseCheckoutLogic) balancePayment(u *user.User, o *order.Order) err // Create balance log if regular balance was used if balanceUsed > 0 { - balanceLog := &user.BalanceLog{ - UserId: u.Id, - Amount: balanceUsed, - Type: 3, // Type 3 represents payment deduction - OrderId: o.Id, - Balance: userInfo.Balance, + balanceLog := &log.Balance{ + Amount: balanceUsed, + Type: log.BalanceTypePayment, // Type 3 represents payment deduction + OrderNo: o.OrderNo, + Balance: userInfo.Balance, + Timestamp: time.Now().UnixMilli(), } - err = db.Create(balanceLog).Error + content, _ := balanceLog.Marshal() + err = db.Create(&log.SystemLog{ + Type: log.TypeBalance.Uint8(), + ObjectID: userInfo.Id, + Date: time.Now().Format(time.DateOnly), + Content: string(content), + }).Error if err != nil { return err } diff --git a/internal/logic/public/portal/purchaseLogic.go b/internal/logic/public/portal/purchaseLogic.go index 5bc8786..c4431dc 100644 --- a/internal/logic/public/portal/purchaseLogic.go +++ b/internal/logic/public/portal/purchaseLogic.go @@ -6,18 +6,17 @@ import ( "fmt" "time" - "github.com/perfect-panel/server/pkg/payment" - - "github.com/perfect-panel/server/pkg/constant" - - "github.com/hibiken/asynq" "github.com/perfect-panel/server/internal/model/order" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/constant" "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/payment" "github.com/perfect-panel/server/pkg/tool" "github.com/perfect-panel/server/pkg/xerr" queue "github.com/perfect-panel/server/queue/types" + + "github.com/hibiken/asynq" "github.com/pkg/errors" "gorm.io/gorm" ) @@ -137,13 +136,15 @@ func (l *PurchaseLogic) Purchase(req *types.PortalPurchaseRequest) (resp *types. Password: req.Password, InviteCode: req.InviteCode, } - if _, err = l.svcCtx.Redis.Set(l.ctx, fmt.Sprintf(constant.TempOrderCacheKey, orderInfo.OrderNo), tempOrder.Marshal(), CloseOrderTimeMinutes*time.Minute).Result(); err != nil { + content, _ := tempOrder.Marshal() + + if _, err = l.svcCtx.Redis.Set(l.ctx, fmt.Sprintf(constant.TempOrderCacheKey, orderInfo.OrderNo), string(content), CloseOrderTimeMinutes*time.Minute).Result(); err != nil { l.Errorw("[Purchase] Redis set error", logger.Field("error", err.Error()), logger.Field("order_no", orderInfo.OrderNo)) return err } l.Infow("[Purchase] Guest order", logger.Field("order_no", orderInfo.OrderNo), logger.Field("identifier", req.Identifier)) // save guest order - if err := l.svcCtx.OrderModel.Insert(l.ctx, orderInfo, tx); err != nil { + if err = l.svcCtx.OrderModel.Insert(l.ctx, orderInfo, tx); err != nil { return err } return nil diff --git a/internal/logic/public/portal/queryPurchaseOrderLogic.go b/internal/logic/public/portal/queryPurchaseOrderLogic.go index bb1b8c3..d8e4795 100644 --- a/internal/logic/public/portal/queryPurchaseOrderLogic.go +++ b/internal/logic/public/portal/queryPurchaseOrderLogic.go @@ -95,7 +95,7 @@ func (l *QueryPurchaseOrderLogic) handleTemporaryOrder(orderInfo *order.Order, r } // Validate user and email - if err := l.validateUserAndEmail(orderInfo, req.Identifier, req.Identifier); err != nil { + if err = l.validateUserAndEmail(orderInfo, req.AuthType, req.Identifier); err != nil { return "", err } diff --git a/internal/logic/public/subscribe/queryApplicationConfigLogic.go b/internal/logic/public/subscribe/queryApplicationConfigLogic.go deleted file mode 100644 index fa939da..0000000 --- a/internal/logic/public/subscribe/queryApplicationConfigLogic.go +++ /dev/null @@ -1,116 +0,0 @@ -package subscribe - -import ( - "context" - - "github.com/perfect-panel/server/internal/model/application" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - "gorm.io/gorm" - - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" -) - -type QueryApplicationConfigLogic struct { - logger.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -// Get application config -func NewQueryApplicationConfigLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryApplicationConfigLogic { - return &QueryApplicationConfigLogic{ - Logger: logger.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *QueryApplicationConfigLogic) QueryApplicationConfig() (resp *types.ApplicationResponse, err error) { - resp = &types.ApplicationResponse{} - var applications []*application.Application - err = l.svcCtx.ApplicationModel.Transaction(l.ctx, func(tx *gorm.DB) (err error) { - return tx.Model(applications).Preload("ApplicationVersions").Find(&applications).Error - }) - if err != nil { - l.Errorw("[QueryApplicationConfig] get application error: ", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "get application error: %v", err.Error()) - } - - if len(applications) == 0 { - return resp, nil - } - - for _, app := range applications { - applicationResponse := types.ApplicationResponseInfo{ - Id: app.Id, - Name: app.Name, - Icon: app.Icon, - Description: app.Description, - SubscribeType: app.SubscribeType, - } - applicationVersions := app.ApplicationVersions - if len(applicationVersions) != 0 { - for _, applicationVersion := range applicationVersions { - /*if !applicationVersion.IsDefault { - continue - }*/ - switch applicationVersion.Platform { - case "ios": - applicationResponse.Platform.IOS = append(applicationResponse.Platform.IOS, &types.ApplicationVersion{ - Id: applicationVersion.Id, - Url: applicationVersion.Url, - Version: applicationVersion.Version, - IsDefault: applicationVersion.IsDefault, - Description: applicationVersion.Description, - }) - case "macos": - applicationResponse.Platform.MacOS = append(applicationResponse.Platform.MacOS, &types.ApplicationVersion{ - Id: applicationVersion.Id, - Url: applicationVersion.Url, - Version: applicationVersion.Version, - IsDefault: applicationVersion.IsDefault, - Description: applicationVersion.Description, - }) - case "linux": - applicationResponse.Platform.Linux = append(applicationResponse.Platform.Linux, &types.ApplicationVersion{ - Id: applicationVersion.Id, - Url: applicationVersion.Url, - Version: applicationVersion.Version, - IsDefault: applicationVersion.IsDefault, - Description: applicationVersion.Description, - }) - case "android": - applicationResponse.Platform.Android = append(applicationResponse.Platform.Android, &types.ApplicationVersion{ - Id: applicationVersion.Id, - Url: applicationVersion.Url, - Version: applicationVersion.Version, - IsDefault: applicationVersion.IsDefault, - Description: applicationVersion.Description, - }) - case "windows": - applicationResponse.Platform.Windows = append(applicationResponse.Platform.Windows, &types.ApplicationVersion{ - Id: applicationVersion.Id, - Url: applicationVersion.Url, - Version: applicationVersion.Version, - IsDefault: applicationVersion.IsDefault, - Description: applicationVersion.Description, - }) - case "harmony": - applicationResponse.Platform.Harmony = append(applicationResponse.Platform.Harmony, &types.ApplicationVersion{ - Id: applicationVersion.Id, - Url: applicationVersion.Url, - Version: applicationVersion.Version, - IsDefault: applicationVersion.IsDefault, - Description: applicationVersion.Description, - }) - } - } - } - resp.Applications = append(resp.Applications, applicationResponse) - } - - return -} diff --git a/internal/logic/public/subscribe/querySubscribeListLogic.go b/internal/logic/public/subscribe/querySubscribeListLogic.go index 09dee07..2208559 100644 --- a/internal/logic/public/subscribe/querySubscribeListLogic.go +++ b/internal/logic/public/subscribe/querySubscribeListLogic.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" + "github.com/perfect-panel/server/internal/model/subscribe" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" @@ -27,15 +28,22 @@ func NewQuerySubscribeListLogic(ctx context.Context, svcCtx *svc.ServiceContext) } } -func (l *QuerySubscribeListLogic) QuerySubscribeList() (resp *types.QuerySubscribeListResponse, err error) { +func (l *QuerySubscribeListLogic) QuerySubscribeList(req *types.QuerySubscribeListRequest) (resp *types.QuerySubscribeListResponse, err error) { - data, err := l.svcCtx.SubscribeModel.QuerySubscribeList(l.ctx) + total, data, err := l.svcCtx.SubscribeModel.FilterList(l.ctx, &subscribe.FilterParams{ + Page: 1, + Size: 9999, + Language: req.Language, + Sell: true, + DefaultLanguage: true, + }) if err != nil { l.Errorw("[QuerySubscribeListLogic] Database Error", logger.Field("error", err.Error())) return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "QuerySubscribeList error: %v", err.Error()) } + resp = &types.QuerySubscribeListResponse{ - Total: int64(len(data)), + Total: total, } list := make([]types.Subscribe, len(data)) for i, item := range data { diff --git a/internal/logic/public/user/getLoginLogLogic.go b/internal/logic/public/user/getLoginLogLogic.go index ce61fa8..a6637f4 100644 --- a/internal/logic/public/user/getLoginLogLogic.go +++ b/internal/logic/public/user/getLoginLogLogic.go @@ -3,13 +3,13 @@ package user import ( "context" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/pkg/constant" "github.com/perfect-panel/server/internal/model/user" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" "github.com/perfect-panel/server/pkg/xerr" "github.com/pkg/errors" ) @@ -35,15 +35,34 @@ func (l *GetLoginLogLogic) GetLoginLog(req *types.GetLoginLogRequest) (resp *typ logger.Error("current user is not found in context") return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access") } - data, total, err := l.svcCtx.UserModel.FilterLoginLogList(l.ctx, req.Page, req.Size, &user.LoginLogFilterParams{ - UserId: u.Id, + data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: req.Page, + Size: req.Size, + Type: log.TypeLogin.Uint8(), + ObjectID: u.Id, }) if err != nil { l.Errorw("find login log failed:", logger.Field("error", err.Error()), logger.Field("user_id", u.Id)) return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find login log failed: %v", err.Error()) } list := make([]types.UserLoginLog, 0) - tool.DeepCopy(&list, data) + + for _, datum := range data { + var content log.Login + if err = content.Unmarshal([]byte(datum.Content)); err != nil { + l.Errorf("[GetUserLoginLogs] unmarshal login log content failed: %v", err.Error()) + continue + } + list = append(list, types.UserLoginLog{ + Id: datum.Id, + UserId: datum.ObjectID, + LoginIP: content.LoginIP, + UserAgent: content.UserAgent, + Success: content.Success, + Timestamp: datum.CreatedAt.UnixMilli(), + }) + } + return &types.GetLoginLogResponse{ Total: total, List: list, diff --git a/internal/logic/public/user/getSubscribeLogLogic.go b/internal/logic/public/user/getSubscribeLogLogic.go index a24308b..eeb51b9 100644 --- a/internal/logic/public/user/getSubscribeLogLogic.go +++ b/internal/logic/public/user/getSubscribeLogLogic.go @@ -3,13 +3,13 @@ package user import ( "context" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/pkg/constant" "github.com/perfect-panel/server/internal/model/user" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" "github.com/perfect-panel/server/pkg/xerr" "github.com/pkg/errors" ) @@ -20,7 +20,7 @@ type GetSubscribeLogLogic struct { svcCtx *svc.ServiceContext } -// Get Subscribe Log +// NewGetSubscribeLogLogic Get Subscribe Log func NewGetSubscribeLogLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetSubscribeLogLogic { return &GetSubscribeLogLogic{ Logger: logger.WithContext(ctx), @@ -35,15 +35,34 @@ func (l *GetSubscribeLogLogic) GetSubscribeLog(req *types.GetSubscribeLogRequest logger.Error("current user is not found in context") return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access") } - data, total, err := l.svcCtx.UserModel.FilterSubscribeLogList(l.ctx, req.Page, req.Size, &user.SubscribeLogFilterParams{ - UserId: u.Id, + data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: req.Page, + Size: req.Size, + Type: log.TypeSubscribe.Uint8(), + ObjectID: u.Id, // filter by current user id }) if err != nil { l.Errorw("[GetUserSubscribeLogs] Get User Subscribe Logs Error:", logger.Field("err", err.Error())) return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Get User Subscribe Logs Error") } var list []types.UserSubscribeLog - tool.DeepCopy(&list, data) + + for _, item := range data { + var content log.Subscribe + if err = content.Unmarshal([]byte(item.Content)); err != nil { + l.Errorf("[GetUserSubscribeLogs] unmarshal subscribe log content failed: %v", err.Error()) + continue + } + list = append(list, types.UserSubscribeLog{ + Id: item.Id, + UserId: item.ObjectID, + UserSubscribeId: content.UserSubscribeId, + Token: content.Token, + IP: content.ClientIP, + UserAgent: content.UserAgent, + Timestamp: item.CreatedAt.UnixMilli(), + }) + } return &types.GetSubscribeLogResponse{ List: list, diff --git a/internal/logic/public/user/queryUserAffiliateLogic.go b/internal/logic/public/user/queryUserAffiliateLogic.go index e0435da..7c8e731 100644 --- a/internal/logic/public/user/queryUserAffiliateLogic.go +++ b/internal/logic/public/user/queryUserAffiliateLogic.go @@ -3,6 +3,7 @@ package user import ( "context" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/pkg/constant" "github.com/perfect-panel/server/internal/model/user" @@ -44,14 +45,20 @@ func (l *QueryUserAffiliateLogic) QueryUserAffiliate() (resp *types.QueryUserAff if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Query User Affiliate failed: %v", err) } - err = l.svcCtx.UserModel.Transaction(l.ctx, func(db *gorm.DB) error { - return db.Model(&user.CommissionLog{}). - Where("user_id = ?", u.Id). - Select("COALESCE(SUM(amount), 0)"). - Scan(&sum).Error + data, _, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: 1, + Size: 99999, + Type: log.TypeCommission.Uint8(), + ObjectID: u.Id, }) - if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Query User Affiliate failed: %v", err) + + for _, datum := range data { + content := log.Commission{} + if err = content.Unmarshal([]byte(datum.Content)); err != nil { + l.Errorf("[QueryUserAffiliate] unmarshal comission log failed: %v", err.Error()) + continue + } + sum += content.Amount } return &types.QueryUserAffiliateCountResponse{ diff --git a/internal/logic/public/user/queryUserBalanceLogLogic.go b/internal/logic/public/user/queryUserBalanceLogLogic.go index 2a3c72d..e8c6d8f 100644 --- a/internal/logic/public/user/queryUserBalanceLogLogic.go +++ b/internal/logic/public/user/queryUserBalanceLogLogic.go @@ -3,17 +3,15 @@ package user import ( "context" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/pkg/constant" "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - "gorm.io/gorm" - "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" ) type QueryUserBalanceLogLogic struct { @@ -22,7 +20,7 @@ type QueryUserBalanceLogLogic struct { svcCtx *svc.ServiceContext } -// Query User Balance Log +// NewQueryUserBalanceLogLogic Query User Balance Log func NewQueryUserBalanceLogLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryUserBalanceLogLogic { return &QueryUserBalanceLogLogic{ Logger: logger.WithContext(ctx), @@ -37,19 +35,37 @@ func (l *QueryUserBalanceLogLogic) QueryUserBalanceLog() (resp *types.QueryUserB logger.Error("current user is not found in context") return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access") } - var data []*user.BalanceLog - var total int64 - // Query User Balance Log - err = l.svcCtx.UserModel.Transaction(l.ctx, func(db *gorm.DB) error { - return db.Model(&user.BalanceLog{}).Order("created_at DESC").Where("user_id = ?", u.Id).Count(&total).Find(&data).Error + + data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: 1, + Size: 99999, + Type: log.TypeBalance.Uint8(), + ObjectID: u.Id, }) if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Query User Balance Log failed: %v", err) + l.Errorw("[QueryUserBalanceLog] Query User Balance Log Error:", logger.Field("err", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Query User Balance Log Error") } - resp = &types.QueryUserBalanceLogListResponse{ - List: make([]types.UserBalanceLog, 0), + + list := make([]types.BalanceLog, 0) + for _, datum := range data { + var content log.Balance + if err = content.Unmarshal([]byte(datum.Content)); err != nil { + l.Errorf("[QueryUserBalanceLog] unmarshal balance log content failed: %v", err.Error()) + continue + } + list = append(list, types.BalanceLog{ + UserId: datum.ObjectID, + Amount: content.Amount, + Type: content.Type, + OrderNo: content.OrderNo, + Balance: content.Balance, + Timestamp: content.Timestamp, + }) + } + + return &types.QueryUserBalanceLogListResponse{ Total: total, - } - tool.DeepCopy(&resp.List, data) - return + List: list, + }, nil } diff --git a/internal/logic/public/user/queryUserCommissionLogLogic.go b/internal/logic/public/user/queryUserCommissionLogLogic.go index 8038197..c005828 100644 --- a/internal/logic/public/user/queryUserCommissionLogLogic.go +++ b/internal/logic/public/user/queryUserCommissionLogLogic.go @@ -3,17 +3,15 @@ package user import ( "context" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/pkg/constant" "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - "gorm.io/gorm" - "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" ) type QueryUserCommissionLogLogic struct { @@ -32,22 +30,40 @@ func NewQueryUserCommissionLogLogic(ctx context.Context, svcCtx *svc.ServiceCont } func (l *QueryUserCommissionLogLogic) QueryUserCommissionLog(req *types.QueryUserCommissionLogListRequest) (resp *types.QueryUserCommissionLogListResponse, err error) { - var data []*user.CommissionLog u, ok := l.ctx.Value(constant.CtxKeyUser).(*user.User) if !ok { logger.Error("current user is not found in context") return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access") } - err = l.svcCtx.UserModel.Transaction(l.ctx, func(db *gorm.DB) error { - return db.Order("id desc").Limit(req.Size).Offset((req.Page-1)*req.Size).Where("user_id = ?", u.Id).Find(&data).Error + data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: req.Page, + Size: req.Size, + Type: log.TypeCommission.Uint8(), + ObjectID: u.Id, }) if err != nil { l.Errorw("Query User Commission Log failed", logger.Field("error", err.Error())) return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Query User Commission Log failed: %v", err) } var list []types.CommissionLog - tool.DeepCopy(&list, data) + + for _, datum := range data { + var content log.Commission + if err = content.Unmarshal([]byte(datum.Content)); err != nil { + l.Errorf("unmarshal commission log content failed: %v", err.Error()) + continue + } + list = append(list, types.CommissionLog{ + UserId: datum.ObjectID, + Type: content.Type, + Amount: content.Amount, + OrderNo: content.OrderNo, + Timestamp: content.Timestamp, + }) + } + return &types.QueryUserCommissionLogListResponse{ - List: list, + List: list, + Total: total, }, nil } diff --git a/internal/logic/public/user/unsubscribeLogic.go b/internal/logic/public/user/unsubscribeLogic.go index 9df80d5..d3390fe 100644 --- a/internal/logic/public/user/unsubscribeLogic.go +++ b/internal/logic/public/user/unsubscribeLogic.go @@ -2,8 +2,11 @@ package user import ( "context" + "time" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/pkg/constant" + "github.com/perfect-panel/server/pkg/tool" "github.com/perfect-panel/server/pkg/xerr" "github.com/pkg/errors" @@ -46,6 +49,14 @@ func (l *UnsubscribeLogic) Unsubscribe(req *types.UnsubscribeRequest) error { return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "FindOneSubscribe failed: %v", err.Error()) } + activate := []uint8{0, 1, 2} + + if !tool.Contains(activate, userSub.Status) { + // Only active (2) or paused (5) subscriptions can be cancelled + l.Errorw("Subscription status invalid for cancellation", logger.Field("userSubscribeId", userSub.Id), logger.Field("status", userSub.Status)) + return errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "Subscription status invalid for cancellation") + } + // Calculate the remaining amount to refund based on unused subscription time/traffic remainingAmount, err := CalculateRemainingAmount(l.ctx, l.svcCtx, req.Id) if err != nil { @@ -55,12 +66,8 @@ func (l *UnsubscribeLogic) Unsubscribe(req *types.UnsubscribeRequest) error { // Process unsubscription in a database transaction to ensure data consistency err = l.svcCtx.UserModel.Transaction(l.ctx, func(db *gorm.DB) error { // Find and update subscription status to cancelled (status = 4) - var userSub user.Subscribe - if err = db.Model(&user.Subscribe{}).Where("id = ?", req.Id).First(&userSub).Error; err != nil { - return err - } userSub.Status = 4 // Set status to cancelled - if err = l.svcCtx.UserModel.UpdateSubscribe(l.ctx, &userSub); err != nil { + if err = l.svcCtx.UserModel.UpdateSubscribe(l.ctx, userSub); err != nil { return err } @@ -91,30 +98,44 @@ func (l *UnsubscribeLogic) Unsubscribe(req *types.UnsubscribeRequest) error { // Create balance log entry only if there's an actual regular balance refund balanceRefundAmount := balance - u.Balance if balanceRefundAmount > 0 { - balanceLog := user.BalanceLog{ - UserId: userSub.UserId, - OrderId: userSub.OrderId, - Amount: balanceRefundAmount, - Type: 4, // Type 4 represents refund transaction - Balance: balance, + balanceLog := log.Balance{ + OrderNo: orderInfo.OrderNo, + Amount: balanceRefundAmount, + Type: log.BalanceTypeRefund, // Type 4 represents refund transaction + Balance: balance, + Timestamp: time.Now().UnixMilli(), } - if err := db.Model(&user.BalanceLog{}).Create(&balanceLog).Error; err != nil { + content, _ := balanceLog.Marshal() + + if err := db.Model(&log.SystemLog{}).Create(&log.SystemLog{ + Type: log.TypeBalance.Uint8(), + Date: time.Now().Format(time.DateOnly), + ObjectID: u.Id, + Content: string(content), + }).Error; err != nil { return err } } // Create gift amount log entry if there's a gift balance refund if gift > 0 { - giftLog := user.GiftAmountLog{ - UserId: userSub.UserId, - UserSubscribeId: userSub.Id, - OrderNo: orderInfo.OrderNo, - Type: 1, // Type 1 represents gift amount increase - Amount: gift, - Balance: u.GiftAmount + gift, - Remark: "Unsubscribe refund", + + giftLog := log.Gift{ + SubscribeId: userSub.Id, + OrderNo: orderInfo.OrderNo, + Type: log.GiftTypeIncrease, // Type 1 represents gift amount increase + Amount: gift, + Balance: u.GiftAmount + gift, + Remark: "Unsubscribe refund", } - if err := db.Model(&user.GiftAmountLog{}).Create(&giftLog).Error; err != nil { + content, _ := giftLog.Marshal() + + if err := db.Model(&log.SystemLog{}).Create(&log.SystemLog{ + Type: log.TypeGift.Uint8(), + Date: time.Now().Format(time.DateOnly), + ObjectID: u.Id, + Content: string(content), + }).Error; err != nil { return err } // Update user's gift amount diff --git a/internal/logic/server/constant.go b/internal/logic/server/constant.go index 0c54202..55ecc26 100644 --- a/internal/logic/server/constant.go +++ b/internal/logic/server/constant.go @@ -1,3 +1,83 @@ package server -const Unchanged = "Unchanged" +const ( + Unchanged = "Unchanged" + ShadowSocks = "shadowsocks" + Vmess = "vmess" + Vless = "vless" + Trojan = "trojan" + AnyTLS = "anytls" + Tuic = "tuic" + Hysteria2 = "hysteria2" +) + +type SecurityConfig struct { + SNI string `json:"sni"` + AllowInsecure *bool `json:"allow_insecure"` + Fingerprint string `json:"fingerprint"` + RealityServerAddress string `json:"reality_server_addr"` + RealityServerPort int `json:"reality_server_port"` + RealityPrivateKey string `json:"reality_private_key"` + RealityPublicKey string `json:"reality_public_key"` + RealityShortId string `json:"reality_short_id"` + RealityMldsa65seed string `json:"reality_mldsa65seed"` +} + +type TransportConfig struct { + Path string `json:"path"` + Host string `json:"host"` + ServiceName string `json:"service_name"` + DisableSNI bool `json:"disable_sni"` + ReduceRtt bool `json:"reduce_rtt"` + UDPRelayMode string `json:"udp_relay_mode"` + CongestionController string `json:"congestion_controller"` +} + +type VlessNode struct { + Port uint16 `json:"port"` + Flow string `json:"flow"` + Network string `json:"transport"` + TransportConfig *TransportConfig `json:"transport_config"` + Security string `json:"security"` + SecurityConfig *SecurityConfig `json:"security_config"` +} + +type VmessNode struct { + Port uint16 `json:"port"` + Network string `json:"transport"` + TransportConfig *TransportConfig `json:"transport_config"` + Security string `json:"security"` + SecurityConfig *SecurityConfig `json:"security_config"` +} + +type ShadowsocksNode struct { + Port uint16 `json:"port"` + Cipher string `json:"method"` + ServerKey string `json:"server_key"` +} + +type TrojanNode struct { + Port uint16 `json:"port"` + Network string `json:"transport"` + TransportConfig *TransportConfig `json:"transport_config"` + Security string `json:"security"` + SecurityConfig *SecurityConfig `json:"security_config"` +} + +type AnyTLSNode struct { + Port uint16 `json:"port"` + SecurityConfig *SecurityConfig `json:"security_config"` +} + +type TuicNode struct { + Port uint16 `json:"port"` + SecurityConfig *SecurityConfig `json:"security_config"` +} + +type Hysteria2Node struct { + Port uint16 `json:"port"` + HopPorts string `json:"hop_ports"` + HopInterval int `json:"hop_interval"` + ObfsPassword string `json:"obfs_password"` + SecurityConfig *SecurityConfig `json:"security_config"` +} diff --git a/internal/logic/server/getServerConfigLogic.go b/internal/logic/server/getServerConfigLogic.go index 7c8eaa9..125f451 100644 --- a/internal/logic/server/getServerConfigLogic.go +++ b/internal/logic/server/getServerConfigLogic.go @@ -6,8 +6,8 @@ import ( "fmt" "github.com/gin-gonic/gin" + "github.com/perfect-panel/server/internal/model/node" - "github.com/perfect-panel/server/internal/config" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" @@ -21,7 +21,7 @@ type GetServerConfigLogic struct { svcCtx *svc.ServiceContext } -// Get server config +// NewGetServerConfigLogic Get server config func NewGetServerConfigLogic(ctx *gin.Context, svcCtx *svc.ServiceContext) *GetServerConfigLogic { return &GetServerConfigLogic{ Logger: logger.WithContext(ctx.Request.Context()), @@ -31,7 +31,7 @@ func NewGetServerConfigLogic(ctx *gin.Context, svcCtx *svc.ServiceContext) *GetS } func (l *GetServerConfigLogic) GetServerConfig(req *types.GetServerConfigRequest) (resp *types.GetServerConfigResponse, err error) { - cacheKey := fmt.Sprintf("%s%d", config.ServerConfigCacheKey, req.ServerId) + cacheKey := fmt.Sprintf("%s%d:%s", node.ServerConfigCacheKey, req.ServerId, req.Protocol) cache, err := l.svcCtx.Redis.Get(l.ctx, cacheKey).Result() if err == nil { if cache != "" { @@ -42,7 +42,7 @@ func (l *GetServerConfigLogic) GetServerConfig(req *types.GetServerConfigRequest return nil, xerr.StatusNotModified } l.ctx.Header("ETag", etag) - resp := &types.GetServerConfigResponse{} + resp = &types.GetServerConfigResponse{} err = json.Unmarshal([]byte(cache), resp) if err != nil { l.Errorw("[ServerConfigCacheKey] json unmarshal error", logger.Field("error", err.Error())) @@ -51,21 +51,21 @@ func (l *GetServerConfigLogic) GetServerConfig(req *types.GetServerConfigRequest return resp, nil } } - nodeInfo, err := l.svcCtx.ServerModel.FindOne(l.ctx, req.ServerId) + data, err := l.svcCtx.NodeModel.FindOneServer(l.ctx, req.ServerId) if err != nil { l.Errorw("[GetServerConfig] FindOne error", logger.Field("error", err.Error())) return nil, err } - cfg := make(map[string]interface{}) - err = json.Unmarshal([]byte(nodeInfo.Config), &cfg) + + protocols, err := data.UnmarshalProtocols() if err != nil { - l.Errorw("[GetServerConfig] json unmarshal error", logger.Field("error", err.Error())) return nil, err } - - if nodeInfo.Protocol == "shadowsocks" { - if value, ok := cfg["server_key"]; ok && value != "" { - cfg["server_key"] = base64.StdEncoding.EncodeToString([]byte(value.(string))) + var cfg map[string]interface{} + for _, protocol := range protocols { + if protocol.Type == req.Protocol { + cfg = l.compatible(protocol) + break } } @@ -74,18 +74,162 @@ func (l *GetServerConfigLogic) GetServerConfig(req *types.GetServerConfigRequest PullInterval: l.svcCtx.Config.Node.NodePullInterval, PushInterval: l.svcCtx.Config.Node.NodePushInterval, }, - Protocol: nodeInfo.Protocol, + Protocol: req.Protocol, Config: cfg, } - data, err := json.Marshal(resp) + c, err := json.Marshal(resp) if err != nil { l.Errorw("[GetServerConfig] json marshal error", logger.Field("error", err.Error())) return nil, err } - etag := tool.GenerateETag(data) + etag := tool.GenerateETag(c) l.ctx.Header("ETag", etag) - if err = l.svcCtx.Redis.Set(l.ctx, cacheKey, data, -1).Err(); err != nil { + if err = l.svcCtx.Redis.Set(l.ctx, cacheKey, c, -1).Err(); err != nil { l.Errorw("[GetServerConfig] redis set error", logger.Field("error", err.Error())) } + // Check If-None-Match header + match := l.ctx.GetHeader("If-None-Match") + if match == etag { + return nil, xerr.StatusNotModified + } + return resp, nil } + +func (l *GetServerConfigLogic) compatible(config node.Protocol) map[string]interface{} { + var result interface{} + switch config.Type { + case ShadowSocks: + result = ShadowsocksNode{ + Port: config.Port, + Cipher: config.Cipher, + ServerKey: base64.StdEncoding.EncodeToString([]byte(config.ServerKey)), + } + case Vless: + result = VlessNode{ + Port: config.Port, + Flow: config.Flow, + Network: config.Transport, + TransportConfig: &TransportConfig{ + Path: config.Path, + Host: config.Host, + ServiceName: config.ServiceName, + DisableSNI: config.DisableSNI, + ReduceRtt: config.ReduceRtt, + UDPRelayMode: config.UDPRelayMode, + CongestionController: config.CongestionController, + }, + Security: config.Security, + SecurityConfig: &SecurityConfig{ + SNI: config.SNI, + AllowInsecure: &config.AllowInsecure, + Fingerprint: config.Fingerprint, + RealityServerAddress: config.RealityServerAddr, + RealityServerPort: config.RealityServerPort, + RealityPrivateKey: config.RealityPrivateKey, + RealityPublicKey: config.RealityPublicKey, + RealityShortId: config.RealityShortId, + }, + } + case Vmess: + result = VmessNode{ + Port: config.Port, + Network: config.Transport, + TransportConfig: &TransportConfig{ + Path: config.Path, + Host: config.Host, + ServiceName: config.ServiceName, + DisableSNI: config.DisableSNI, + ReduceRtt: config.ReduceRtt, + UDPRelayMode: config.UDPRelayMode, + CongestionController: config.CongestionController, + }, + Security: config.Security, + SecurityConfig: &SecurityConfig{ + SNI: config.SNI, + AllowInsecure: &config.AllowInsecure, + Fingerprint: config.Fingerprint, + RealityServerAddress: config.RealityServerAddr, + RealityServerPort: config.RealityServerPort, + RealityPrivateKey: config.RealityPrivateKey, + RealityPublicKey: config.RealityPublicKey, + RealityShortId: config.RealityShortId, + }, + } + case Trojan: + result = TrojanNode{ + Port: config.Port, + Network: config.Transport, + TransportConfig: &TransportConfig{ + Path: config.Path, + Host: config.Host, + ServiceName: config.ServiceName, + DisableSNI: config.DisableSNI, + ReduceRtt: config.ReduceRtt, + UDPRelayMode: config.UDPRelayMode, + CongestionController: config.CongestionController, + }, + Security: config.Security, + SecurityConfig: &SecurityConfig{ + SNI: config.SNI, + AllowInsecure: &config.AllowInsecure, + Fingerprint: config.Fingerprint, + RealityServerAddress: config.RealityServerAddr, + RealityServerPort: config.RealityServerPort, + RealityPrivateKey: config.RealityPrivateKey, + RealityPublicKey: config.RealityPublicKey, + RealityShortId: config.RealityShortId, + }, + } + case AnyTLS: + result = AnyTLSNode{ + Port: config.Port, + SecurityConfig: &SecurityConfig{ + SNI: config.SNI, + AllowInsecure: &config.AllowInsecure, + Fingerprint: config.Fingerprint, + RealityServerAddress: config.RealityServerAddr, + RealityServerPort: config.RealityServerPort, + RealityPrivateKey: config.RealityPrivateKey, + RealityPublicKey: config.RealityPublicKey, + RealityShortId: config.RealityShortId, + }, + } + case Tuic: + result = TuicNode{ + Port: config.Port, + SecurityConfig: &SecurityConfig{ + SNI: config.SNI, + AllowInsecure: &config.AllowInsecure, + Fingerprint: config.Fingerprint, + RealityServerAddress: config.RealityServerAddr, + RealityServerPort: config.RealityServerPort, + RealityPrivateKey: config.RealityPrivateKey, + RealityPublicKey: config.RealityPublicKey, + RealityShortId: config.RealityShortId, + }, + } + case Hysteria2: + result = Hysteria2Node{ + Port: config.Port, + HopPorts: config.HopPorts, + HopInterval: config.HopInterval, + ObfsPassword: config.ObfsPassword, + SecurityConfig: &SecurityConfig{ + SNI: config.SNI, + AllowInsecure: &config.AllowInsecure, + Fingerprint: config.Fingerprint, + RealityServerAddress: config.RealityServerAddr, + RealityServerPort: config.RealityServerPort, + RealityPrivateKey: config.RealityPrivateKey, + RealityPublicKey: config.RealityPublicKey, + RealityShortId: config.RealityShortId, + }, + } + + } + var resp map[string]interface{} + s, _ := json.Marshal(result) + _ = json.Unmarshal(s, &resp) + return resp +} diff --git a/internal/logic/server/getServerUserListLogic.go b/internal/logic/server/getServerUserListLogic.go index bf4a6a3..70ea51f 100644 --- a/internal/logic/server/getServerUserListLogic.go +++ b/internal/logic/server/getServerUserListLogic.go @@ -3,10 +3,12 @@ package server import ( "encoding/json" "fmt" + "strings" "github.com/gin-gonic/gin" + "github.com/perfect-panel/server/internal/model/node" + "github.com/perfect-panel/server/internal/model/subscribe" - "github.com/perfect-panel/server/internal/config" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" @@ -21,7 +23,7 @@ type GetServerUserListLogic struct { svcCtx *svc.ServiceContext } -// Get user list +// NewGetServerUserListLogic Get user list func NewGetServerUserListLogic(ctx *gin.Context, svcCtx *svc.ServiceContext) *GetServerUserListLogic { return &GetServerUserListLogic{ Logger: logger.WithContext(ctx.Request.Context()), @@ -31,30 +33,53 @@ func NewGetServerUserListLogic(ctx *gin.Context, svcCtx *svc.ServiceContext) *Ge } func (l *GetServerUserListLogic) GetServerUserList(req *types.GetServerUserListRequest) (resp *types.GetServerUserListResponse, err error) { - cacheKey := fmt.Sprintf("%s%d", config.ServerUserListCacheKey, req.ServerId) + cacheKey := fmt.Sprintf("%s%d", node.ServerUserListCacheKey, req.ServerId) cache, err := l.svcCtx.Redis.Get(l.ctx, cacheKey).Result() - if err == nil { - if cache != "" { - etag := tool.GenerateETag([]byte(cache)) - resp := &types.GetServerUserListResponse{} - // Check If-None-Match header - if match := l.ctx.GetHeader("If-None-Match"); match == etag { - return nil, xerr.StatusNotModified - } - l.ctx.Header("ETag", etag) - err = json.Unmarshal([]byte(cache), resp) - if err != nil { - l.Errorw("[ServerUserListCacheKey] json unmarshal error", logger.Field("error", err.Error())) - return nil, err - } - return resp, nil + if cache != "" { + etag := tool.GenerateETag([]byte(cache)) + resp = &types.GetServerUserListResponse{} + // Check If-None-Match header + if match := l.ctx.GetHeader("If-None-Match"); match == etag { + return nil, xerr.StatusNotModified } + l.ctx.Header("ETag", etag) + err = json.Unmarshal([]byte(cache), resp) + if err != nil { + l.Errorw("[ServerUserListCacheKey] json unmarshal error", logger.Field("error", err.Error())) + return nil, err + } + return resp, nil } - server, err := l.svcCtx.ServerModel.FindOne(l.ctx, req.ServerId) + server, err := l.svcCtx.NodeModel.FindOneServer(l.ctx, req.ServerId) if err != nil { return nil, err } - subs, err := l.svcCtx.SubscribeModel.QuerySubscribeIdsByServerIdAndServerGroupId(l.ctx, server.Id, server.GroupId) + + _, nodes, err := l.svcCtx.NodeModel.FilterNodeList(l.ctx, &node.FilterNodeParams{ + Page: 1, + Size: 1000, + ServerId: []int64{server.Id}, + Protocol: req.Protocol, + }) + if err != nil { + l.Errorw("FilterNodeList error", logger.Field("error", err.Error())) + return nil, err + } + var nodeTag []string + var nodeIds []int64 + for _, n := range nodes { + nodeIds = append(nodeIds, n.Id) + if n.Tags != "" { + nodeTag = append(nodeTag, strings.Split(n.Tags, ",")...) + } + } + + _, subs, err := l.svcCtx.SubscribeModel.FilterList(l.ctx, &subscribe.FilterParams{ + Page: 1, + Size: 9999, + Node: nodeIds, + Tags: nodeTag, + }) if err != nil { l.Errorw("QuerySubscribeIdsByServerIdAndServerGroupId error", logger.Field("error", err.Error())) return nil, err @@ -76,16 +101,10 @@ func (l *GetServerUserListLogic) GetServerUserList(req *types.GetServerUserListR return nil, err } for _, datum := range data { - speedLimit := server.SpeedLimit - if (int(sub.SpeedLimit) < server.SpeedLimit && sub.SpeedLimit != 0) || - (int(sub.SpeedLimit) > server.SpeedLimit && sub.SpeedLimit == 0) { - speedLimit = int(sub.SpeedLimit) - } - users = append(users, types.ServerUser{ Id: datum.Id, UUID: datum.UUID, - SpeedLimit: int64(speedLimit), + SpeedLimit: sub.SpeedLimit, DeviceLimit: sub.DeviceLimit, }) } @@ -106,5 +125,9 @@ func (l *GetServerUserListLogic) GetServerUserList(req *types.GetServerUserListR if err != nil { l.Errorw("[ServerUserListCacheKey] redis set error", logger.Field("error", err.Error())) } + // Check If-None-Match header + if match := l.ctx.GetHeader("If-None-Match"); match == etag { + return nil, xerr.StatusNotModified + } return resp, nil } diff --git a/internal/logic/server/pushOnlineUsersLogic.go b/internal/logic/server/pushOnlineUsersLogic.go index b8ce501..5b17656 100644 --- a/internal/logic/server/pushOnlineUsersLogic.go +++ b/internal/logic/server/pushOnlineUsersLogic.go @@ -5,7 +5,7 @@ import ( "errors" "fmt" - "github.com/perfect-panel/server/internal/model/cache" + "github.com/perfect-panel/server/internal/model/node" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" @@ -40,26 +40,30 @@ func (l *PushOnlineUsersLogic) PushOnlineUsers(req *types.OnlineUsersRequest) er } // Find server info - _, err := l.svcCtx.ServerModel.FindOne(l.ctx, req.ServerId) + _, err := l.svcCtx.NodeModel.FindOneServer(l.ctx, req.ServerId) if err != nil { l.Errorw("[PushOnlineUsers] FindOne error", logger.Field("error", err)) return fmt.Errorf("server not found: %w", err) } - userOnlineIp := make([]cache.NodeOnlineUser, 0) + onlineUsers := make(node.OnlineUserSubscribe) for _, user := range req.Users { - userOnlineIp = append(userOnlineIp, cache.NodeOnlineUser{ - SID: user.SID, - IP: user.IP, - }) + if online, ok := onlineUsers[user.SID]; ok { + // If user already exists, update IP if different + online = append(online, user.IP) + onlineUsers[user.SID] = online + } else { + // New user, add to map + onlineUsers[user.SID] = []string{user.IP} + } } - err = l.svcCtx.NodeCache.AddOnlineUserIP(l.ctx, userOnlineIp) + err = l.svcCtx.NodeModel.UpdateOnlineUserSubscribe(l.ctx, req.ServerId, req.Protocol, onlineUsers) if err != nil { l.Errorw("[PushOnlineUsers] cache operation error", logger.Field("error", err)) return err } - err = l.svcCtx.NodeCache.UpdateNodeOnlineUser(l.ctx, req.ServerId, userOnlineIp) + err = l.svcCtx.NodeModel.UpdateOnlineUserSubscribeGlobal(l.ctx, onlineUsers) if err != nil { l.Errorw("[PushOnlineUsers] cache operation error", logger.Field("error", err)) diff --git a/internal/logic/server/queryServerProtocolConfigLogic.go b/internal/logic/server/queryServerProtocolConfigLogic.go new file mode 100644 index 0000000..6322959 --- /dev/null +++ b/internal/logic/server/queryServerProtocolConfigLogic.go @@ -0,0 +1,47 @@ +package server + +import ( + "context" + + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/tool" +) + +type QueryServerProtocolConfigLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// NewQueryServerProtocolConfigLogic Get Server Protocol Config +func NewQueryServerProtocolConfigLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryServerProtocolConfigLogic { + return &QueryServerProtocolConfigLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *QueryServerProtocolConfigLogic) QueryServerProtocolConfig(req *types.QueryServerConfigRequest) (resp *types.QueryServerConfigResponse, err error) { + // find server + data, err := l.svcCtx.NodeModel.FindOneServer(l.ctx, req.ServerID) + if err != nil { + l.Errorf("[GetServerProtocols] FindOneServer Error: %s", err.Error()) + return nil, err + } + + // handler protocols + var protocols []types.Protocol + dst, err := data.UnmarshalProtocols() + if err != nil { + l.Errorf("[FilterServerList] UnmarshalProtocols Error: %s", err.Error()) + return nil, err + } + tool.DeepCopy(&protocols, dst) + + return &types.QueryServerConfigResponse{ + Protocols: protocols, + }, nil +} diff --git a/internal/logic/server/serverPushStatusLogic.go b/internal/logic/server/serverPushStatusLogic.go index 7e5ff91..d7c0bad 100644 --- a/internal/logic/server/serverPushStatusLogic.go +++ b/internal/logic/server/serverPushStatusLogic.go @@ -3,8 +3,9 @@ package server import ( "context" "errors" + "time" - "github.com/perfect-panel/server/internal/model/cache" + "github.com/perfect-panel/server/internal/model/node" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" @@ -16,7 +17,7 @@ type ServerPushStatusLogic struct { svcCtx *svc.ServiceContext } -// Push server status +// NewServerPushStatusLogic Push server status func NewServerPushStatusLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ServerPushStatusLogic { return &ServerPushStatusLogic{ Logger: logger.WithContext(ctx), @@ -27,12 +28,12 @@ func NewServerPushStatusLogic(ctx context.Context, svcCtx *svc.ServiceContext) * func (l *ServerPushStatusLogic) ServerPushStatus(req *types.ServerPushStatusRequest) error { // Find server info - serverInfo, err := l.svcCtx.ServerModel.FindOne(l.ctx, req.ServerId) + serverInfo, err := l.svcCtx.NodeModel.FindOneServer(l.ctx, req.ServerId) if err != nil || serverInfo.Id <= 0 { l.Errorw("[PushOnlineUsers] FindOne error", logger.Field("error", err)) return errors.New("server not found") } - err = l.svcCtx.NodeCache.UpdateNodeStatus(l.ctx, req.ServerId, cache.NodeStatus{ + err = l.svcCtx.NodeModel.UpdateStatusCache(l.ctx, req.ServerId, &node.Status{ Cpu: req.Cpu, Mem: req.Mem, Disk: req.Disk, @@ -42,5 +43,14 @@ func (l *ServerPushStatusLogic) ServerPushStatus(req *types.ServerPushStatusRequ l.Errorw("[ServerPushStatus] UpdateNodeStatus error", logger.Field("error", err)) return errors.New("update node status failed") } + now := time.Now() + serverInfo.LastReportedAt = &now + + err = l.svcCtx.NodeModel.UpdateServer(l.ctx, serverInfo) + if err != nil { + l.Errorw("[ServerPushStatus] UpdateServer error", logger.Field("error", err)) + return nil + } + return nil } diff --git a/internal/logic/server/serverPushUserTrafficLogic.go b/internal/logic/server/serverPushUserTrafficLogic.go index 3481340..d94e827 100644 --- a/internal/logic/server/serverPushUserTrafficLogic.go +++ b/internal/logic/server/serverPushUserTrafficLogic.go @@ -3,9 +3,9 @@ package server import ( "context" "encoding/json" + "time" "github.com/hibiken/asynq" - "github.com/perfect-panel/server/internal/model/cache" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" @@ -32,7 +32,7 @@ func NewServerPushUserTrafficLogic(ctx context.Context, svcCtx *svc.ServiceConte func (l *ServerPushUserTrafficLogic) ServerPushUserTraffic(req *types.ServerPushUserTrafficRequest) error { // Find server info - serverInfo, err := l.svcCtx.ServerModel.FindOne(l.ctx, req.ServerId) + serverInfo, err := l.svcCtx.NodeModel.FindOneServer(l.ctx, req.ServerId) if err != nil { l.Errorw("[PushOnlineUsers] FindOne error", logger.Field("error", err)) return errors.New("server not found") @@ -40,23 +40,9 @@ func (l *ServerPushUserTrafficLogic) ServerPushUserTraffic(req *types.ServerPush // Create traffic task var request task.TrafficStatistics - var userTraffic []cache.UserTraffic request.ServerId = serverInfo.Id tool.DeepCopy(&request.Logs, req.Traffic) - tool.DeepCopy(&userTraffic, req.Traffic) - // update today traffic rank - err = l.svcCtx.NodeCache.AddNodeTodayTraffic(l.ctx, serverInfo.Id, userTraffic) - if err != nil { - l.Errorw("[ServerPushUserTraffic] AddNodeTodayTraffic error", logger.Field("error", err)) - return errors.New("add node today traffic error") - } - for _, user := range req.Traffic { - if err = l.svcCtx.NodeCache.AddUserTodayTraffic(l.ctx, user.SID, user.Upload, user.Download); err != nil { - l.Errorw("[ServerPushUserTraffic] AddUserTodayTraffic error", logger.Field("error", err)) - continue - } - } // Push traffic task val, _ := json.Marshal(request) t := asynq.NewTask(task.ForthwithTrafficStatistics, val, asynq.MaxRetry(3)) @@ -66,5 +52,15 @@ func (l *ServerPushUserTrafficLogic) ServerPushUserTraffic(req *types.ServerPush } else { l.Infow("[ServerPushUserTraffic] Push traffic task success", logger.Field("task", t), logger.Field("info", info)) } + + // Update server last reported time + now := time.Now() + serverInfo.LastReportedAt = &now + + err = l.svcCtx.NodeModel.UpdateServer(l.ctx, serverInfo) + if err != nil { + l.Errorw("[ServerPushUserTraffic] UpdateServer error", logger.Field("error", err)) + return nil + } return nil } diff --git a/internal/logic/subscribe/subscribeLogic.go b/internal/logic/subscribe/subscribeLogic.go index 063e13e..f523e89 100644 --- a/internal/logic/subscribe/subscribeLogic.go +++ b/internal/logic/subscribe/subscribeLogic.go @@ -6,12 +6,10 @@ import ( "strings" "time" - "github.com/perfect-panel/server/pkg/adapter" - "github.com/perfect-panel/server/pkg/adapter/shadowrocket" - "github.com/perfect-panel/server/pkg/adapter/surfboard" - "github.com/perfect-panel/server/pkg/adapter/surge" - - "github.com/perfect-panel/server/internal/model/server" + "github.com/perfect-panel/server/adapter" + "github.com/perfect-panel/server/internal/model/client" + "github.com/perfect-panel/server/internal/model/log" + "github.com/perfect-panel/server/internal/model/node" "github.com/perfect-panel/server/internal/model/user" @@ -39,37 +37,123 @@ func NewSubscribeLogic(ctx *gin.Context, svc *svc.ServiceContext) *SubscribeLogi } } -func (l *SubscribeLogic) Generate(req *types.SubscribeRequest) (*types.SubscribeResponse, error) { - userSub, err := l.getUserSubscribe(req.Token) +func (l *SubscribeLogic) Handler(req *types.SubscribeRequest) (resp *types.SubscribeResponse, err error) { + // query client list + clients, err := l.svc.ClientModel.List(l.ctx.Request.Context()) if err != nil { + l.Errorw("[SubscribeLogic] Query client list failed", logger.Field("error", err.Error())) + return nil, err + } + + userAgent := strings.ToLower(l.ctx.Request.UserAgent()) + + var targetApp, defaultApp *client.SubscribeApplication + + for _, item := range clients { + u := strings.ToLower(item.UserAgent) + if item.IsDefault { + defaultApp = item + } + + if strings.Contains(userAgent, u) { + // Special handling for Stash + if strings.Contains(userAgent, "stash") && !strings.Contains(u, "stash") { + continue + } + targetApp = item + break + } + } + if targetApp == nil { + l.Debugf("[SubscribeLogic] No matching client found", logger.Field("userAgent", userAgent)) + if defaultApp == nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "No matching client found for user agent: %s", userAgent) + } + targetApp = defaultApp + } + // Find user subscribe by token + userSubscribe, err := l.getUserSubscribe(req.Token) + if err != nil { + l.Errorw("[SubscribeLogic] Get user subscribe failed", logger.Field("error", err.Error()), logger.Field("token", req.Token)) return nil, err } var subscribeStatus = false defer func() { - l.logSubscribeActivity(subscribeStatus, userSub, req) + l.logSubscribeActivity(subscribeStatus, userSubscribe, req) }() + // find subscribe info + subscribeInfo, err := l.svc.SubscribeModel.FindOne(l.ctx.Request.Context(), userSubscribe.SubscribeId) + if err != nil { + l.Errorw("[SubscribeLogic] Find subscribe info failed", logger.Field("error", err.Error()), logger.Field("subscribeId", userSubscribe.SubscribeId)) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Find subscribe info failed: %v", err.Error()) + } - servers, err := l.getServers(userSub) + // Find server list by user subscribe + servers, err := l.getServers(userSubscribe) if err != nil { return nil, err } + a := adapter.NewAdapter( + targetApp.SubscribeTemplate, + adapter.WithServers(servers), + adapter.WithSiteName(l.svc.Config.Site.SiteName), + adapter.WithSubscribeName(subscribeInfo.Name), + adapter.WithOutputFormat(targetApp.OutputFormat), + adapter.WithUserInfo(adapter.User{ + Password: userSubscribe.UUID, + ExpiredAt: userSubscribe.ExpireTime, + Download: userSubscribe.Download, + Upload: userSubscribe.Upload, + Traffic: userSubscribe.Traffic, + SubscribeURL: l.getSubscribeV2URL(req.Token), + }), + ) - rules, err := l.getRules() + // Get client config + adapterClient, err := a.Client() if err != nil { - return nil, err + l.Errorw("[SubscribeLogic] Client error", logger.Field("error", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(500), "Client error: %v", err.Error()) + } + bytes, err := adapterClient.Build() + if err != nil { + l.Errorw("[SubscribeLogic] Build client config failed", logger.Field("error", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(500), "Build client config failed: %v", err.Error()) } - resp, headerInfo, err := l.buildClientConfig(req, userSub, servers, rules) - if err != nil { - return nil, err + var formats = []string{"json", "yaml", "conf"} + + for _, format := range formats { + if format == strings.ToLower(targetApp.OutputFormat) { + l.ctx.Header("content-disposition", fmt.Sprintf("attachment;filename*=UTF-8''%s.%s", url.QueryEscape(l.svc.Config.Site.SiteName), format)) + l.ctx.Header("Content-Type", "application/octet-stream; charset=UTF-8") + + } } + resp = &types.SubscribeResponse{ + Config: bytes, + Header: fmt.Sprintf( + "upload=%d;download=%d;total=%d;expire=%d", + userSubscribe.Upload, userSubscribe.Download, userSubscribe.Traffic, userSubscribe.ExpireTime.Unix(), + ), + } subscribeStatus = true - return &types.SubscribeResponse{ - Config: resp, - Header: headerInfo, - }, nil + return +} + +func (l *SubscribeLogic) getSubscribeV2URL(token string) string { + if l.svc.Config.Subscribe.PanDomain { + return fmt.Sprintf("https://%s", l.ctx.Request.Host) + } + + if l.svc.Config.Subscribe.SubscribeDomain != "" { + domains := strings.Split(l.svc.Config.Subscribe.SubscribeDomain, "\n") + return fmt.Sprintf("https://%s%s?token=%s", domains[0], l.svc.Config.Subscribe.SubscribePath, token) + } + + return fmt.Sprintf("https://%s%s?token=%s&", l.ctx.Request.Host, l.svc.Config.Subscribe.SubscribePath, token) } func (l *SubscribeLogic) getUserSubscribe(token string) (*user.Subscribe, error) { @@ -92,19 +176,27 @@ func (l *SubscribeLogic) logSubscribeActivity(subscribeStatus bool, userSub *use return } - err := l.svc.UserModel.InsertSubscribeLog(l.ctx.Request.Context(), &user.SubscribeLog{ - UserId: userSub.UserId, - UserSubscribeId: userSub.Id, + subscribeLog := log.Subscribe{ Token: req.Token, - IP: l.ctx.ClientIP(), - UserAgent: l.ctx.Request.UserAgent(), + UserAgent: req.UA, + ClientIP: l.ctx.ClientIP(), + UserSubscribeId: userSub.Id, + } + + content, _ := subscribeLog.Marshal() + + err := l.svc.LogModel.Insert(l.ctx.Request.Context(), &log.SystemLog{ + Type: log.TypeSubscribe.Uint8(), + ObjectID: userSub.UserId, // log user id + Date: time.Now().Format(time.DateOnly), + Content: string(content), }) if err != nil { l.Errorw("[Generate Subscribe]insert subscribe log error: %v", logger.Field("error", err.Error())) } } -func (l *SubscribeLogic) getServers(userSub *user.Subscribe) ([]*server.Server, error) { +func (l *SubscribeLogic) getServers(userSub *user.Subscribe) ([]*node.Node, error) { if l.isSubscriptionExpired(userSub) { return l.createExpiredServers(), nil } @@ -115,49 +207,61 @@ func (l *SubscribeLogic) getServers(userSub *user.Subscribe) ([]*server.Server, return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find subscribe details error: %v", err.Error()) } - serverIds := tool.StringToInt64Slice(subDetails.Server) - groupIds := tool.StringToInt64Slice(subDetails.ServerGroup) + nodeIds := tool.StringToInt64Slice(subDetails.Nodes) + tags := strings.Split(subDetails.NodeTags, ",") - l.Debugf("[Generate Subscribe]serverIds: %v, groupIds: %v", serverIds, groupIds) + l.Debugf("[Generate Subscribe]nodes: %v, NodeTags: %v", nodeIds, tags) - servers, err := l.svc.ServerModel.FindServerDetailByGroupIdsAndIds(l.ctx.Request.Context(), groupIds, serverIds) + _, nodes, err := l.svc.NodeModel.FilterNodeList(l.ctx.Request.Context(), &node.FilterNodeParams{ + Page: 1, + Size: 1000, + ServerId: nodeIds, + Tag: tool.RemoveDuplicateElements(tags...), + Preload: true, + }) - l.Debugf("[Query Subscribe]found servers: %v", len(servers)) + l.Debugf("[Query Subscribe]found servers: %v", len(nodes)) if err != nil { l.Errorw("[Generate Subscribe]find server details error: %v", logger.Field("error", err.Error())) return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find server details error: %v", err.Error()) } - logger.Debugf("[Generate Subscribe]found servers: %v", len(servers)) - return servers, nil + logger.Debugf("[Generate Subscribe]found servers: %v", len(nodes)) + return nodes, nil } func (l *SubscribeLogic) isSubscriptionExpired(userSub *user.Subscribe) bool { return userSub.ExpireTime.Unix() < time.Now().Unix() && userSub.ExpireTime.Unix() != 0 } -func (l *SubscribeLogic) createExpiredServers() []*server.Server { +func (l *SubscribeLogic) createExpiredServers() []*node.Node { enable := true host := l.getFirstHostLine() - return []*server.Server{ + return []*node.Node{ { - Name: "Subscribe Expired", - ServerAddr: "127.0.0.1", - RelayMode: "none", - Protocol: "shadowsocks", - Config: "{\"method\":\"aes-256-gcm\",\"port\":1}", - Enable: &enable, - Sort: 0, + Name: "Subscribe Expired", + Tags: "", + Port: 18080, + Address: "127.0.0.1", + Server: &node.Server{ + Name: "Subscribe Expired", + Protocols: "[{\"type:\"\"shadowsocks\",\"cipher\":\"aes-256-gcm\",\"port\":1}]", + }, + Protocol: "shadowsocks", + Enabled: &enable, }, { - Name: host, - ServerAddr: "127.0.0.1", - RelayMode: "none", - Protocol: "shadowsocks", - Config: "{\"method\":\"aes-256-gcm\",\"port\":1}", - Enable: &enable, - Sort: 0, + Name: host, + Tags: "", + Port: 18080, + Address: "127.0.0.1", + Server: &node.Server{ + Name: "Subscribe Expired", + Protocols: "[{\"type:\"\"shadowsocks\",\"cipher\":\"aes-256-gcm\",\"port\":1}]", + }, + Protocol: "shadowsocks", + Enabled: &enable, }, } } @@ -170,175 +274,3 @@ func (l *SubscribeLogic) getFirstHostLine() string { } return host } - -func (l *SubscribeLogic) getRules() ([]*server.RuleGroup, error) { - rules, err := l.svc.ServerModel.QueryAllRuleGroup(l.ctx) - if err != nil { - l.Errorw("[Generate Subscribe]find rule group error: %v", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find rule group error: %v", err.Error()) - } - return rules, nil -} - -func (l *SubscribeLogic) buildClientConfig(req *types.SubscribeRequest, userSub *user.Subscribe, servers []*server.Server, rules []*server.RuleGroup) ([]byte, string, error) { - tags := make(map[string][]*server.Server) - - serverTags, err := l.svc.ServerModel.FindServerTags(l.ctx) - if err != nil { - l.Errorw("[Generate Subscribe]find server tags error: %v", logger.Field("error", err.Error())) - return nil, "", errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find server tags error: %v", err.Error()) - } - // Deduplicate tags - serverTags = tool.RemoveDuplicateElements(serverTags...) - for _, tag := range serverTags { - s, err := l.svc.ServerModel.FindServersByTag(l.ctx.Request.Context(), tag) - if err != nil { - l.Errorw("[Generate Subscribe]find servers by tag error: %v", logger.Field("error", err.Error())) - continue - } - if len(s) > 0 { - tags[tag] = s - } - } - - proxyManager := adapter.NewAdapter(&adapter.Config{ - Nodes: servers, - Rules: rules, - Tags: tags, - }) - clientType := l.getClientType(req) - var resp []byte - - l.Logger.Info(fmt.Sprintf("[Generate Subscribe] %s", clientType), logger.Field("ua", req.UA), logger.Field("flag", req.Flag)) - - switch clientType { - case "clash": - resp, err = proxyManager.BuildClash(userSub.UUID) - if err != nil { - l.Errorw("[Generate Subscribe] build clash error", logger.Field("error", err.Error())) - return nil, "", errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "build clash error: %v", err.Error()) - } - l.setClashHeaders() - case "sing-box": - resp, err = proxyManager.BuildSingbox(userSub.UUID) - if err != nil { - l.Errorw("[Generate Subscribe] build sing-box error", logger.Field("error", err.Error())) - return nil, "", errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "build sing-box error: %v", err.Error()) - } - case "quantumult": - resp = []byte(proxyManager.BuildQuantumultX(userSub.UUID)) - case "shadowrocket": - resp = proxyManager.BuildShadowrocket(userSub.UUID, shadowrocket.UserInfo{ - Upload: userSub.Upload, - Download: userSub.Download, - TotalTraffic: userSub.Traffic, - ExpiredDate: userSub.ExpireTime, - }) - case "loon": - resp = proxyManager.BuildLoon(userSub.UUID) - l.setLoonHeaders() - case "surfboard": - subsURL := l.getSubscribeURL(userSub.Token, "surfboard") - resp = proxyManager.BuildSurfboard(l.svc.Config.Site.SiteName, surfboard.UserInfo{ - Upload: userSub.Upload, - Download: userSub.Download, - TotalTraffic: userSub.Traffic, - ExpiredDate: userSub.ExpireTime, - UUID: userSub.UUID, - SubscribeURL: subsURL, - }) - l.setSurfboardHeaders() - case "v2rayn": - resp = proxyManager.BuildV2rayN(userSub.UUID) - case "surge": - subsURL := l.getSubscribeURL(userSub.Token, "surge") - resp = proxyManager.BuildSurge(l.svc.Config.Site.SiteName, surge.UserInfo{ - UUID: userSub.UUID, - Upload: userSub.Upload, - Download: userSub.Download, - TotalTraffic: userSub.Traffic, - ExpiredDate: userSub.ExpireTime, - SubscribeURL: subsURL, - }) - l.setSurgeHeaders() - default: - resp = proxyManager.BuildGeneral(userSub.UUID) - } - - headerInfo := fmt.Sprintf("upload=%d;download=%d;total=%d;expire=%d", - userSub.Upload, userSub.Download, userSub.Traffic, userSub.ExpireTime.Unix()) - - return resp, headerInfo, nil -} - -func (l *SubscribeLogic) setClashHeaders() { - l.ctx.Header("content-disposition", fmt.Sprintf("attachment;filename*=UTF-8''%s", url.QueryEscape(l.svc.Config.Site.SiteName))) - l.ctx.Header("Profile-Update-Interval", "24") - l.ctx.Header("Content-Type", "application/octet-stream; charset=UTF-8") -} - -func (l *SubscribeLogic) setSurfboardHeaders() { - l.ctx.Header("content-disposition", fmt.Sprintf("attachment;filename*=UTF-8''%s.conf", url.QueryEscape(l.svc.Config.Site.SiteName))) - l.ctx.Header("Content-Type", "application/octet-stream; charset=UTF-8") -} - -func (l *SubscribeLogic) setSurgeHeaders() { - l.ctx.Header("content-disposition", fmt.Sprintf("attachment;filename*=UTF-8''%s.conf", url.QueryEscape(l.svc.Config.Site.SiteName))) - l.ctx.Header("Content-Type", "application/octet-stream; charset=UTF-8") -} - -func (l *SubscribeLogic) setLoonHeaders() { - l.ctx.Header("content-disposition", fmt.Sprintf("attachment;filename*=UTF-8''%s.conf", url.QueryEscape(l.svc.Config.Site.SiteName))) - l.ctx.Header("Content-Type", "application/octet-stream; charset=UTF-8") -} - -func (l *SubscribeLogic) getSubscribeURL(token, flag string) string { - if l.svc.Config.Subscribe.PanDomain { - return fmt.Sprintf("https://%s", l.ctx.Request.Host) - } - - if l.svc.Config.Subscribe.SubscribeDomain != "" { - domains := strings.Split(l.svc.Config.Subscribe.SubscribeDomain, "\n") - return fmt.Sprintf("https://%s%s?token=%s&flag=%s", domains[0], l.svc.Config.Subscribe.SubscribePath, token, flag) - } - - return fmt.Sprintf("https://%s%s?token=%s&flag=surfboard", l.ctx.Request.Host, l.svc.Config.Subscribe.SubscribePath, token) -} - -func (l *SubscribeLogic) getClientType(req *types.SubscribeRequest) string { - clientTypeMap := map[string]string{ - "clash": "clash", - "meta": "clash", - "sing-box": "sing-box", - "hiddify": "sing-box", - "surge": "surge", - "quantumult": "quantumult", - "shadowrocket": "shadowrocket", - "loon": "loon", - "surfboard": "surfboard", - "v2rayn": "v2rayn", - } - - findClient := func(s string) string { - s = strings.ToLower(strings.TrimSpace(s)) - if s == "" { - return "" - } - - for key, clientType := range clientTypeMap { - if strings.Contains(s, key) { - return clientType - } - } - - return "" - } - - // 优先检查Flag参数 - if typ := findClient(req.Flag); typ != "" { - return typ - } - - // 其次检查UA参数 - return findClient(req.UA) -} diff --git a/internal/logic/subscribe/v2Logic.go b/internal/logic/subscribe/v2Logic.go deleted file mode 100644 index c4ed247..0000000 --- a/internal/logic/subscribe/v2Logic.go +++ /dev/null @@ -1,127 +0,0 @@ -package subscribe - -import ( - "fmt" - "net/url" - "strings" - - "github.com/perfect-panel/server/adapter" - "github.com/perfect-panel/server/internal/model/client" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" -) - -func (l *SubscribeLogic) V2(req *types.SubscribeRequest) (resp *types.SubscribeResponse, err error) { - // query client list - clients, err := l.svc.ClientModel.List(l.ctx.Request.Context()) - if err != nil { - l.Errorw("[SubscribeLogic] Query client list failed", logger.Field("error", err.Error())) - return nil, err - } - - userAgent := strings.ToLower(l.ctx.Request.UserAgent()) - - var targetApp, defaultApp *client.SubscribeApplication - - for _, item := range clients { - u := strings.ToLower(item.UserAgent) - if item.IsDefault { - defaultApp = item - } - if strings.Contains(userAgent, u) { - targetApp = item - break - } - } - if targetApp == nil { - l.Debugf("[SubscribeLogic] No matching client found", logger.Field("userAgent", userAgent)) - if defaultApp == nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "No matching client found for user agent: %s", userAgent) - } - targetApp = defaultApp - } - // Find user subscribe by token - userSubscribe, err := l.getUserSubscribe(req.Token) - if err != nil { - l.Errorw("[SubscribeLogic] Get user subscribe failed", logger.Field("error", err.Error()), logger.Field("token", req.Token)) - return nil, err - } - - var subscribeStatus = false - defer func() { - l.logSubscribeActivity(subscribeStatus, userSubscribe, req) - }() - // find subscribe info - subscribeInfo, err := l.svc.SubscribeModel.FindOne(l.ctx.Request.Context(), userSubscribe.SubscribeId) - if err != nil { - l.Errorw("[SubscribeLogic] Find subscribe info failed", logger.Field("error", err.Error()), logger.Field("subscribeId", userSubscribe.SubscribeId)) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Find subscribe info failed: %v", err.Error()) - } - - // Find server list by user subscribe - servers, err := l.getServers(userSubscribe) - if err != nil { - return nil, err - } - a := adapter.NewAdapter( - targetApp.SubscribeTemplate, - adapter.WithServers(servers), - adapter.WithSiteName(l.svc.Config.Site.SiteName), - adapter.WithSubscribeName(subscribeInfo.Name), - adapter.WithOutputFormat(targetApp.OutputFormat), - adapter.WithUserInfo(adapter.User{ - Password: userSubscribe.UUID, - ExpiredAt: userSubscribe.ExpireTime, - Download: userSubscribe.Download, - Upload: userSubscribe.Upload, - Traffic: userSubscribe.Traffic, - SubscribeURL: l.getSubscribeV2URL(req.Token), - }), - ) - - // Get client config - adapterClient, err := a.Client() - if err != nil { - l.Errorw("[SubscribeLogic] Client error", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(500), "Client error: %v", err.Error()) - } - bytes, err := adapterClient.Build() - if err != nil { - l.Errorw("[SubscribeLogic] Build client config failed", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(500), "Build client config failed: %v", err.Error()) - } - - var formats = []string{"json", "yaml", "conf"} - - for _, format := range formats { - if format == strings.ToLower(targetApp.OutputFormat) { - l.ctx.Header("content-disposition", fmt.Sprintf("attachment;filename*=UTF-8''%s.%s", url.QueryEscape(l.svc.Config.Site.SiteName), format)) - l.ctx.Header("Content-Type", "application/octet-stream; charset=UTF-8") - - } - } - - resp = &types.SubscribeResponse{ - Config: bytes, - Header: fmt.Sprintf( - "upload=%d;download=%d;total=%d;expire=%d", - userSubscribe.Upload, userSubscribe.Download, userSubscribe.Traffic, userSubscribe.ExpireTime.Unix(), - ), - } - return -} - -func (l *SubscribeLogic) getSubscribeV2URL(token string) string { - if l.svc.Config.Subscribe.PanDomain { - return fmt.Sprintf("https://%s", l.ctx.Request.Host) - } - - if l.svc.Config.Subscribe.SubscribeDomain != "" { - domains := strings.Split(l.svc.Config.Subscribe.SubscribeDomain, "\n") - return fmt.Sprintf("https://%s%s?token=%s", domains[0], l.svc.Config.Subscribe.SubscribePath, token) - } - - return fmt.Sprintf("https://%s%s?token=%s&", l.ctx.Request.Host, l.svc.Config.Subscribe.SubscribePath, token) -} diff --git a/internal/middleware/appMiddleware.go b/internal/middleware/appMiddleware.go deleted file mode 100644 index c480f22..0000000 --- a/internal/middleware/appMiddleware.go +++ /dev/null @@ -1,282 +0,0 @@ -package middleware - -import ( - "bufio" - "bytes" - "encoding/json" - "fmt" - "io" - "net" - "net/http" - "strings" - - "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/result" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - - "github.com/gin-gonic/gin" - "github.com/perfect-panel/server/internal/svc" - pkgaes "github.com/perfect-panel/server/pkg/aes" -) - -const ( - noWritten = -1 - defaultStatus = http.StatusOK - key = "123456" -) - -func AppMiddleware(svc *svc.ServiceContext) func(c *gin.Context) { - return func(c *gin.Context) { - if !strings.Contains(c.Request.URL.Path, "/v1/app") { - c.Next() - return - } - rw := NewResponseWriter(c, svc) - if !rw.Decrypt() { - result.HttpResult(c, nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidCiphertext), "Invalid ciphertext")) - c.Abort() - return - } - c.Writer = rw - c.Next() - rw.FlushAbort() - } -} - -func NewResponseWriter(c *gin.Context, srvCtx *svc.ServiceContext) (rw *ResponseWriter) { - rw = &ResponseWriter{ - c: c, - body: new(bytes.Buffer), - ResponseWriter: c.Writer, - } - applicationConfig, err := srvCtx.ApplicationModel.FindOneConfig(c, 1) - if err != nil { - logger.Errorf("[AppMiddleware] find application config error: %v", err.Error()) - return - } - if strings.ToUpper(applicationConfig.EncryptionMethod) == "AES" && applicationConfig.EncryptionKey != "" { - rw.encryptionKey = applicationConfig.EncryptionKey - rw.encryptionMethod = applicationConfig.EncryptionMethod - rw.encryption = true - } - return -} - -func (rw *ResponseWriter) Encrypt() { - if !rw.encryption { - return - } - buf := rw.body.Bytes() - params := map[string]interface{}{} - err := json.Unmarshal(buf, ¶ms) - if err != nil { - return - } - data := params["data"] - if data != nil { - var jsonData []byte - str, ok := data.(string) - if ok { - jsonData = []byte(str) - } else { - jsonData, _ = json.Marshal(data) - } - encrypt, iv, err := pkgaes.Encrypt(jsonData, rw.encryptionKey) - if err != nil { - return - } - params["data"] = map[string]interface{}{ - "data": encrypt, - "time": iv, - } - - } - marshal, _ := json.Marshal(params) - rw.body.Reset() - rw.body.Write(marshal) -} - -func (rw *ResponseWriter) Decrypt() bool { - if !rw.encryption { - return true - } - - //判断url链接中是否存在data和iv数据,存在就进行解密并设置回去 - query := rw.c.Request.URL.Query() - dataStr := query.Get("data") - timeStr := query.Get("time") - if dataStr != "" && timeStr != "" { - decrypt, err := pkgaes.Decrypt(dataStr, rw.encryptionKey, timeStr) - if err == nil { - params := map[string]interface{}{} - err = json.Unmarshal([]byte(decrypt), ¶ms) - if err == nil { - for k, v := range params { - query.Set(k, fmt.Sprintf("%v", v)) - } - query.Del("data") - query.Del("time") - rw.c.Request.RequestURI = fmt.Sprintf("%s?%s", rw.c.Request.RequestURI[:strings.Index(rw.c.Request.RequestURI, "?")], query.Encode()) - rw.c.Request.URL.RawQuery = query.Encode() - } - } - } - - //判断body是否存在数据,存在就尝试解密,并设置回去 - body, err := io.ReadAll(rw.c.Request.Body) - if err != nil { - return true - } - - if len(body) == 0 { - return true - } - - params := map[string]interface{}{} - err = json.Unmarshal(body, ¶ms) - data := params["data"] - nonce := params["time"] - if err != nil || data == nil { - return false - } - - str, ok := data.(string) - if !ok { - return false - } - iv, ok := nonce.(string) - if !ok { - return false - } - - decrypt, err := pkgaes.Decrypt(str, rw.encryptionKey, iv) - if err != nil { - return false - } - rw.c.Request.Body = io.NopCloser(bytes.NewBuffer([]byte(decrypt))) - return true -} - -func (rw *ResponseWriter) FlushAbort() { - defer rw.c.Abort() - responseBody := rw.body.String() - fmt.Println("Original Response Body:", responseBody) - rw.flush = true - if rw.encryption { - rw.Encrypt() - } - _, err := rw.Write(rw.body.Bytes()) - if err != nil { - return - } -} - -type ResponseWriter struct { - http.ResponseWriter - size int - status int - flush bool - body *bytes.Buffer - c *gin.Context - encryption bool - encryptionKey string - encryptionMethod string -} - -func (rw *ResponseWriter) Unwrap() http.ResponseWriter { - return rw.ResponseWriter -} - -//nolint:unused -func (rw *ResponseWriter) reset(writer http.ResponseWriter) { - rw.ResponseWriter = writer - rw.size = noWritten - rw.status = defaultStatus -} - -func (rw *ResponseWriter) WriteHeader(code int) { - if code > 0 && rw.status != code { - if rw.Written() { - return - } - rw.status = code - } -} - -func (rw *ResponseWriter) WriteHeaderNow() { - if !rw.Written() { - rw.size = 0 - rw.ResponseWriter.WriteHeader(rw.status) - } -} - -func (rw *ResponseWriter) Write(data []byte) (n int, err error) { - if rw.flush { - rw.WriteHeaderNow() - n, err = rw.ResponseWriter.Write(data) - rw.size += n - } else { - rw.body.Write(data) - } - return -} - -func (rw *ResponseWriter) WriteString(s string) (n int, err error) { - if rw.flush { - rw.WriteHeaderNow() - n, err = rw.ResponseWriter.Write([]byte(s)) - rw.size += n - } else { - rw.body.Write([]byte(s)) - } - return -} - -func (rw *ResponseWriter) Status() int { - return rw.status -} - -func (rw *ResponseWriter) Size() int { - return rw.size -} - -func (rw *ResponseWriter) Written() bool { - return rw.size != noWritten -} - -// Hijack implements the http.Hijacker interface. -func (rw *ResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { - if rw.size < 0 { - rw.size = 0 - } - return rw.ResponseWriter.(http.Hijacker).Hijack() -} - -// CloseNotify implements the http.CloseNotifier interface. -func (rw *ResponseWriter) CloseNotify() <-chan bool { - // 通过 r.Context().Done() 来监听请求的取消 - done := rw.c.Request.Context().Done() - closed := make(chan bool) - - // 当上下文被取消时,通过 closed channel 发送通知 - go func() { - <-done - closed <- true - }() - - return closed -} - -// Flush implements the http.Flusher interface. -func (rw *ResponseWriter) Flush() { - rw.WriteHeaderNow() - rw.ResponseWriter.(http.Flusher).Flush() -} - -func (rw *ResponseWriter) Pusher() (pusher http.Pusher) { - if pusher, ok := rw.ResponseWriter.(http.Pusher); ok { - return pusher - } - return nil -} diff --git a/internal/middleware/loggerMiddleware.go b/internal/middleware/loggerMiddleware.go index 43e27ab..7bb2def 100644 --- a/internal/middleware/loggerMiddleware.go +++ b/internal/middleware/loggerMiddleware.go @@ -44,6 +44,9 @@ func LoggerMiddleware(svc *svc.ServiceContext) func(c *gin.Context) { // Start recording logs cost := time.Since(start) responseStatus := c.Writer.Status() + + host := c.Request.Host + logs := []logger.LogField{ { Key: "status", @@ -51,7 +54,7 @@ func LoggerMiddleware(svc *svc.ServiceContext) func(c *gin.Context) { }, { Key: "request", - Value: c.Request.Method + " " + c.Request.URL.String(), + Value: c.Request.Method + " " + host + c.Request.URL.String(), }, { Key: "query", @@ -88,6 +91,10 @@ func LoggerMiddleware(svc *svc.ServiceContext) func(c *gin.Context) { } else { logger.WithContext(c.Request.Context()).Infow("HTTP Request", logs...) } + + if responseStatus == 404 { + logger.WithContext(c.Request.Context()).Debugf("404 Not Found: Host:%s Path:%s IsPanDomain:%v", host, c.Request.URL.Path, svc.Config.Subscribe.PanDomain) + } } } diff --git a/internal/middleware/panDomainMiddleware.go b/internal/middleware/panDomainMiddleware.go index b5ce8eb..518c787 100644 --- a/internal/middleware/panDomainMiddleware.go +++ b/internal/middleware/panDomainMiddleware.go @@ -8,24 +8,47 @@ import ( "github.com/perfect-panel/server/internal/logic/subscribe" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/tool" ) func PanDomainMiddleware(svc *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { if svc.Config.Subscribe.PanDomain && c.Request.URL.Path == "/" { - // intercept browser ua := c.GetHeader("User-Agent") - if ua == "" { - c.String(http.StatusForbidden, "Access denied") - c.Abort() - return - } - browserKeywords := []string{"chrome", "firefox", "safari", "edge", "opera", "micromessenger"} - for _, keyword := range browserKeywords { - lcUA := strings.ToLower(ua) - if strings.Contains(lcUA, keyword) { + + if svc.Config.Subscribe.UserAgentLimit { + if ua == "" { + c.String(http.StatusForbidden, "Access denied") + c.Abort() + return + } + browserKeywords := tool.RemoveDuplicateElements(strings.Split(svc.Config.Subscribe.UserAgentList, "\n")...) + var allow = false + + // query client list + clients, err := svc.ClientModel.List(c.Request.Context()) + if err != nil { + logger.Errorw("[PanDomainMiddleware] Query client list failed", logger.Field("error", err.Error())) + } + for _, item := range clients { + u := strings.ToLower(item.UserAgent) + u = strings.Trim(u, " ") + browserKeywords = append(browserKeywords, u) + } + + for _, keyword := range browserKeywords { + keyword = strings.ToLower(strings.Trim(keyword, " ")) + if keyword == "" { + continue + } + if strings.Contains(strings.ToLower(ua), keyword) { + allow = true + } + } + if !allow { c.String(http.StatusForbidden, "Access denied") c.Abort() return @@ -41,7 +64,7 @@ func PanDomainMiddleware(svc *svc.ServiceContext) func(c *gin.Context) { UA: c.Request.Header.Get("User-Agent"), } l := subscribe.NewSubscribeLogic(c, svc) - resp, err := l.Generate(&request) + resp, err := l.Handler(&request) if err != nil { return } diff --git a/internal/middleware/traceMiddleware.go b/internal/middleware/traceMiddleware.go index a697cb5..6e143a8 100644 --- a/internal/middleware/traceMiddleware.go +++ b/internal/middleware/traceMiddleware.go @@ -9,14 +9,12 @@ import ( "github.com/perfect-panel/server/pkg/constant" "github.com/gin-gonic/gin" - "github.com/google/uuid" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" semconv "go.opentelemetry.io/otel/semconv/v1.24.0" oteltrace "go.opentelemetry.io/otel/trace" "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/logger" "github.com/perfect-panel/server/pkg/trace" ) @@ -71,19 +69,13 @@ func TraceMiddleware(_ *svc.ServiceContext) func(ctx *gin.Context) { ) defer span.End() - requestId, err := uuid.NewV7() - if err != nil { - logger.Errorw( - "failed to generate request id in uuid v7 format, fallback to uuid v4", - logger.Field("error", err), - ) - requestId = uuid.New() - } - c.Header(trace.RequestIdKey, requestId.String()) + requestId := trace.TraceIDFromContext(ctx) + + c.Header(trace.RequestIdKey, requestId) span.SetAttributes(requestAttributes(c.Request)...) span.SetAttributes( - attribute.String("http.request_id", requestId.String()), + attribute.String("http.request_id", requestId), semconv.HTTPRouteKey.String(c.FullPath()), ) // context with request host diff --git a/internal/model/application/application.go b/internal/model/application/application.go deleted file mode 100644 index bc6471f..0000000 --- a/internal/model/application/application.go +++ /dev/null @@ -1,54 +0,0 @@ -package application - -import ( - "time" -) - -type Application struct { - Id int64 `gorm:"primary_key"` - Name string `gorm:"type:varchar(255);default:'';not null;comment:应用名称"` - Icon string `gorm:"type:text;not null;comment:应用图标"` - Description string `gorm:"type:text;comment:更新描述"` - SubscribeType string `gorm:"type:varchar(50);default:'';not null;comment:订阅类型"` - ApplicationVersions []ApplicationVersion - CreatedAt time.Time `gorm:"<-:create;comment:创建时间"` - UpdatedAt time.Time `gorm:"comment:更新时间"` -} - -func (Application) TableName() string { - return "application" -} - -type ApplicationVersion struct { - Id int64 `gorm:"primary_key"` - Url string `gorm:"type:varchar(255);default:'';not null;comment:应用地址"` - Version string `gorm:"type:varchar(255);default:'';not null;comment:应用版本"` - Platform string `gorm:"type:varchar(50);default:'';not null;comment:应用平台"` - IsDefault bool `gorm:"type:tinyint(1);not null;default:0;comment:默认版本"` - Description string `gorm:"type:text;comment:更新描述"` - ApplicationId int64 `gorm:"comment:所属应用"` - CreatedAt time.Time `gorm:"<-:create;comment:创建时间"` - UpdatedAt time.Time `gorm:"comment:更新时间"` -} - -func (ApplicationVersion) TableName() string { - return "application_version" -} - -type ApplicationConfig struct { - Id int64 `gorm:"primary_key"` - AppId int64 `gorm:"type:int;not null;default:0;comment:App id"` - EncryptionKey string `gorm:"type:text;comment:Encryption Key"` - EncryptionMethod string `gorm:"type:varchar(255);comment:Encryption Method"` - Domains string `gorm:"type:text;comment:Domains"` - StartupPicture string `gorm:"type:text;comment:Startup Picture"` - StartupPictureSkipTime int64 `gorm:"type:int;not null;default:0;comment:Startup Picture Skip Time"` - InvitationLink string `gorm:"type:text;comment:Invitation Link"` - KrWebsiteId string `gorm:"type:varchar(255);default:'';comment:Kr Website ID"` - CreatedAt time.Time `gorm:"<-:create;comment:Create Time"` - UpdatedAt time.Time `gorm:"comment:Update Time"` -} - -func (ApplicationConfig) TableName() string { - return "application_config" -} diff --git a/internal/model/application/default.go b/internal/model/application/default.go deleted file mode 100644 index 8245827..0000000 --- a/internal/model/application/default.go +++ /dev/null @@ -1,245 +0,0 @@ -package application - -import ( - "context" - "errors" - "fmt" - - "github.com/perfect-panel/server/internal/config" - "github.com/perfect-panel/server/pkg/cache" - "github.com/redis/go-redis/v9" - "gorm.io/gorm" -) - -var _ Model = (*customApplicationModel)(nil) -var ( - cacheApplicationIdPrefix = "cache:application:id:" - cacheApplicationConfigIdPrefix = "cache:application:config:id:" - cacheApplicationVersionIdPrefix = "cache:application:version:id:" -) - -type ( - Model interface { - applicationModel - customApplicationLogicModel - } - applicationModel interface { - Insert(ctx context.Context, data *Application) error - FindOne(ctx context.Context, id int64) (*Application, error) - Update(ctx context.Context, data *Application) error - Delete(ctx context.Context, id int64) error - InsertVersion(ctx context.Context, data *ApplicationVersion) error - FindOneVersion(ctx context.Context, id int64) (*ApplicationVersion, error) - UpdateVersion(ctx context.Context, data *ApplicationVersion) error - InsertConfig(ctx context.Context, data *ApplicationConfig) error - FindOneConfig(ctx context.Context, id int64) (*ApplicationConfig, error) - UpdateConfig(ctx context.Context, data *ApplicationConfig) error - DeleteVersion(ctx context.Context, id int64) error - Transaction(ctx context.Context, fn func(db *gorm.DB) error) error - } - - customApplicationModel struct { - *defaultApplicationModel - } - defaultApplicationModel struct { - cache.CachedConn - table string - } -) - -func newApplicationModel(db *gorm.DB, c *redis.Client) *defaultApplicationModel { - return &defaultApplicationModel{ - CachedConn: cache.NewConn(db, c), - table: "`Application`", - } -} - -func (m *defaultApplicationModel) getCacheKeys(data *Application) []string { - if data == nil { - return []string{} - } - ApplicationIdKey := fmt.Sprintf("%s%v", cacheApplicationIdPrefix, data.Id) - cacheKeys := []string{ - ApplicationIdKey, - config.ApplicationKey, - } - return cacheKeys -} - -func (m *defaultApplicationModel) Insert(ctx context.Context, data *Application) error { - err := m.ExecCtx(ctx, func(conn *gorm.DB) error { - return conn.Create(&data).Error - }, m.getCacheKeys(data)...) - return err -} - -func (m *defaultApplicationModel) FindOne(ctx context.Context, id int64) (*Application, error) { - ApplicationIdKey := fmt.Sprintf("%s%v", cacheApplicationIdPrefix, id) - var resp Application - err := m.QueryCtx(ctx, &resp, ApplicationIdKey, func(conn *gorm.DB, v interface{}) error { - return conn.Model(&Application{}).Preload("ApplicationVersions").Where("`id` = ?", id).First(&resp).Error - }) - switch { - case err == nil: - return &resp, nil - default: - return nil, err - } -} - -func (m *defaultApplicationModel) Update(ctx context.Context, data *Application) error { - old, err := m.FindOne(ctx, data.Id) - if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - return err - } - err = m.ExecCtx(ctx, func(conn *gorm.DB) error { - db := conn - return db.Save(data).Error - }, m.getCacheKeys(old)...) - return err -} - -func (m *defaultApplicationModel) Delete(ctx context.Context, id int64) error { - data, err := m.FindOne(ctx, id) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil - } - return err - } - err = m.ExecCtx(ctx, func(conn *gorm.DB) error { - db := conn - err = db.Where("application_id = ?", id).Delete(&ApplicationVersion{}).Error - if err != nil { - return err - } - return db.Delete(&Application{}, id).Error - }, m.getCacheKeys(data)...) - return err -} - -func (m *defaultApplicationModel) getVersionCacheKeys(data *ApplicationVersion) []string { - if data == nil { - return []string{} - } - ApplicationVersionIdKey := fmt.Sprintf("%s%v", cacheApplicationVersionIdPrefix, data.Id) - cacheKeys := []string{ - ApplicationVersionIdKey, - config.ApplicationKey, - } - return cacheKeys -} -func (m *defaultApplicationModel) getConfigCacheKeys(data *ApplicationConfig) []string { - if data == nil { - return []string{} - } - ApplicationConfigIdKey := fmt.Sprintf("%s%v", cacheApplicationConfigIdPrefix, data.Id) - cacheKeys := []string{ - ApplicationConfigIdKey, - config.ApplicationKey, - } - return cacheKeys -} - -func (m *defaultApplicationModel) InsertVersion(ctx context.Context, data *ApplicationVersion) error { - err := m.ExecCtx(ctx, func(conn *gorm.DB) error { - return conn.Transaction(func(tx *gorm.DB) error { - if data.IsDefault { - err := tx.Model(&ApplicationVersion{}). - Where("application_id = ? and platform = ? and default_version = ?", data.ApplicationId, data.Platform, data.IsDefault). - Updates(map[string]interface{}{"default_version": false}).Error - if err != nil { - return err - } - } - return tx.Create(&data).Error - }) - }, m.getVersionCacheKeys(data)...) - return err -} - -func (m *defaultApplicationModel) FindOneVersion(ctx context.Context, id int64) (*ApplicationVersion, error) { - ApplicationVersionIdKey := fmt.Sprintf("%s%v", cacheApplicationVersionIdPrefix, id) - var resp ApplicationVersion - err := m.QueryCtx(ctx, &resp, ApplicationVersionIdKey, func(conn *gorm.DB, v interface{}) error { - return conn.Model(&ApplicationVersion{}).Where("`id` = ?", id).First(&resp).Error - }) - switch { - case err == nil: - return &resp, nil - default: - return nil, err - } -} - -func (m *defaultApplicationModel) UpdateVersion(ctx context.Context, data *ApplicationVersion) error { - old, err := m.FindOneVersion(ctx, data.Id) - if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - return err - } - err = m.ExecCtx(ctx, func(conn *gorm.DB) error { - return conn.Transaction(func(tx *gorm.DB) error { - if data.IsDefault { - err := tx.Model(&ApplicationVersion{}). - Where("application_id = ? and platform = ? and default_version = ?", data.ApplicationId, data.Platform, data.IsDefault). - Updates(map[string]interface{}{"default_version": false}).Error - if err != nil { - return err - } - } - return tx.Save(data).Error - }) - }, m.getVersionCacheKeys(old)...) - return err -} - -func (m *defaultApplicationModel) InsertConfig(ctx context.Context, data *ApplicationConfig) error { - err := m.ExecCtx(ctx, func(conn *gorm.DB) error { - return conn.Create(&data).Error - }, m.getConfigCacheKeys(data)...) - return err -} - -func (m *defaultApplicationModel) FindOneConfig(ctx context.Context, id int64) (*ApplicationConfig, error) { - ApplicationConfigIdKey := fmt.Sprintf("%s%v", cacheApplicationConfigIdPrefix, id) - var resp ApplicationConfig - err := m.QueryCtx(ctx, &resp, ApplicationConfigIdKey, func(conn *gorm.DB, v interface{}) error { - return conn.Model(&ApplicationConfig{}).Where("`id` = ?", id).First(&resp).Error - }) - switch { - case err == nil: - return &resp, nil - default: - return nil, err - } -} - -func (m *defaultApplicationModel) UpdateConfig(ctx context.Context, data *ApplicationConfig) error { - old, err := m.FindOneConfig(ctx, data.Id) - if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - return err - } - err = m.ExecCtx(ctx, func(conn *gorm.DB) error { - return conn.Save(data).Error - }, m.getConfigCacheKeys(old)...) - return err -} - -func (m *defaultApplicationModel) DeleteVersion(ctx context.Context, id int64) error { - data, err := m.FindOneVersion(ctx, id) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil - } - return err - } - err = m.ExecCtx(ctx, func(conn *gorm.DB) error { - db := conn - return db.Delete(&ApplicationVersion{}, id).Error - }, m.getVersionCacheKeys(data)...) - return err -} - -func (m *defaultApplicationModel) Transaction(ctx context.Context, fn func(db *gorm.DB) error) error { - return m.TransactCtx(ctx, fn) -} diff --git a/internal/model/application/model.go b/internal/model/application/model.go deleted file mode 100644 index 3bd5b0a..0000000 --- a/internal/model/application/model.go +++ /dev/null @@ -1,16 +0,0 @@ -package application - -import ( - "github.com/redis/go-redis/v9" - "gorm.io/gorm" -) - -type customApplicationLogicModel interface { -} - -// NewModel returns a model for the database table. -func NewModel(conn *gorm.DB, c *redis.Client) Model { - return &customApplicationModel{ - defaultApplicationModel: newApplicationModel(conn, c), - } -} diff --git a/internal/model/cache/constant.go b/internal/model/cache/constant.go deleted file mode 100644 index 5ae995c..0000000 --- a/internal/model/cache/constant.go +++ /dev/null @@ -1,52 +0,0 @@ -package cache - -const ( - // UserTodayUploadTrafficCacheKey 用户当日上传流量 - UserTodayUploadTrafficCacheKey = "node:user_today_upload_traffic" - // UserTodayDownloadTrafficCacheKey 用户当日下载流量 - UserTodayDownloadTrafficCacheKey = "node:user_today_download_traffic" - // UserTodayTotalTrafficCacheKey 用户当日总流量 - UserTodayTotalTrafficCacheKey = "node:user_today_total_traffic" - // NodeTodayUploadTrafficCacheKey 节点当日上传流量 - NodeTodayUploadTrafficCacheKey = "node:node_today_upload_traffic" - // NodeTodayDownloadTrafficCacheKey 节点当日下载流量 - NodeTodayDownloadTrafficCacheKey = "node:node_today_download_traffic" - // NodeTodayTotalTrafficCacheKey 节点当日总流量 - NodeTodayTotalTrafficCacheKey = "node:node_today_total_traffic" - // UserTodayUploadTrafficRankKey 用户当日上传流量排行榜 - UserTodayUploadTrafficRankKey = "node:user_today_upload_traffic_rank" - // UserTodayDownloadTrafficRankKey 用户当日下载流量排行榜 - UserTodayDownloadTrafficRankKey = "node:user_today_download_traffic_rank" - // UserTodayTotalTrafficRankKey 用户当日总流量排行榜 - UserTodayTotalTrafficRankKey = "node:user_today_total_traffic_rank" - // NodeTodayUploadTrafficRankKey 节点当日上传流量排行榜 - NodeTodayUploadTrafficRankKey = "node:node_today_upload_traffic_rank" - // NodeTodayDownloadTrafficRankKey 节点当日下载流量排行榜 - NodeTodayDownloadTrafficRankKey = "node:node_today_download_traffic_rank" - // NodeTodayTotalTrafficRankKey 节点当日总流量排行榜 - NodeTodayTotalTrafficRankKey = "node:node_today_total_traffic_rank" - // NodeOnlineUserCacheKey 节点在线用户 - NodeOnlineUserCacheKey = "node:node_online_user:%d" - // UserOnlineIpCacheKey 用户在线IP - UserOnlineIpCacheKey = "node:user_online_ip:%d" - // AllNodeOnlineUserCacheKey 所有节点在线用户 - AllNodeOnlineUserCacheKey = "node:all_node_online_user" - // NodeStatusCacheKey 节点状态 - NodeStatusCacheKey = "node:status:%d" - // AllNodeDownloadTrafficCacheKey 所有节点下载流量 - AllNodeDownloadTrafficCacheKey = "node:all_node_download_traffic" - // AllNodeUploadTrafficCacheKey 所有节点上传流量 - AllNodeUploadTrafficCacheKey = "node:all_node_upload_traffic" - // YesterdayTotalTrafficRank 昨日节点总流量排行榜 - YesterdayNodeTotalTrafficRank = "node:yesterday_total_traffic_rank" - // YesterdayUploadTrafficRank 昨日节点上传流量排行榜 - YesterdayNodeUploadTrafficRank = "node:yesterday_upload_traffic_rank" - // YesterdayDownloadTrafficRank 昨日节点下载流量排行榜 - YesterdayNodeDownloadTrafficRank = "node:yesterday_download_traffic_rank" - // YesterdayUserTotalTrafficRank 昨日用户总流量排行榜 - YesterdayUserTotalTrafficRank = "node:yesterday_user_total_traffic_rank" - // YesterdayUserUploadTrafficRank 昨日用户上传流量排行榜 - YesterdayUserUploadTrafficRank = "node:yesterday_user_upload_traffic_rank" - // YesterdayUserDownloadTrafficRank 昨日用户下载流量排行榜 - YesterdayUserDownloadTrafficRank = "node:yesterday_user_download_traffic_rank" -) diff --git a/internal/model/cache/node.go b/internal/model/cache/node.go deleted file mode 100644 index 9b65b15..0000000 --- a/internal/model/cache/node.go +++ /dev/null @@ -1,584 +0,0 @@ -package cache - -import ( - "context" - "encoding/json" - "fmt" - "strconv" - "sync" - "time" - - "github.com/perfect-panel/server/pkg/logger" - "github.com/redis/go-redis/v9" -) - -type NodeCacheClient struct { - *redis.Client - resetMutex sync.Mutex -} - -func NewNodeCacheClient(rds *redis.Client) *NodeCacheClient { - return &NodeCacheClient{ - Client: rds, - } -} - -// AddOnlineUserIP adds user's online IP -func (c *NodeCacheClient) AddOnlineUserIP(ctx context.Context, users []NodeOnlineUser) error { - if len(users) == 0 { - // No users to add - return nil - } - - // Use Pipeline to optimize Redis operations - pipe := c.Pipeline() - - // Add user online IPs and clean up expired IPs for each user - for _, user := range users { - if user.SID <= 0 || user.IP == "" { - logger.Errorf("invalid user data: uid=%d, ip=%s", user.SID, user.IP) - continue - } - - key := fmt.Sprintf(UserOnlineIpCacheKey, user.SID) - now := time.Now() - expireTime := now.Add(5 * time.Minute) - - // Clean up expired user online IPs - pipe.ZRemRangeByScore(ctx, key, "0", fmt.Sprintf("%d", now.Unix())) - pipe.ZRemRangeByScore(ctx, AllNodeOnlineUserCacheKey, "0", fmt.Sprintf("%d", now.Unix())) - - // Add or update user online IP - // XX: Only update elements that already exist - // NX: Only add new elements - _ = pipe.ZAdd(ctx, key, redis.Z{ - Score: float64(expireTime.Unix()), - Member: user.IP, - }).Err() - _ = pipe.ZAdd(ctx, AllNodeOnlineUserCacheKey, redis.Z{ - Score: float64(expireTime.Unix()), - Member: user.IP, - }).Err() - - // Set key expiration to 5 minutes (slightly longer than IP expiration) - pipe.Expire(ctx, key, 5*time.Minute) - pipe.Expire(ctx, AllNodeOnlineUserCacheKey, 5*time.Minute) - } - - // Execute all commands - _, err := pipe.Exec(ctx) - if err != nil { - return fmt.Errorf("failed to add node user online ip: %w", err) - } - return nil -} - -// GetUserOnlineIp gets user's online IPs -func (c *NodeCacheClient) GetUserOnlineIp(ctx context.Context, uid int64) ([]string, error) { - if uid <= 0 { - return nil, fmt.Errorf("invalid parameters: uid=%d", uid) - } - - // Get user's online IPs - ips, err := c.ZRevRangeByScore(ctx, fmt.Sprintf(UserOnlineIpCacheKey, uid), &redis.ZRangeBy{ - Min: "0", - Max: fmt.Sprintf("%d", time.Now().Add(5*time.Minute).Unix()), - Offset: 0, - Count: 100, - }).Result() - if err != nil { - return nil, fmt.Errorf("failed to get user online ip: %w", err) - } - return ips, nil -} - -// UpdateNodeOnlineUser updates node's online users and IPs -func (c *NodeCacheClient) UpdateNodeOnlineUser(ctx context.Context, nodeId int64, users []NodeOnlineUser) error { - if nodeId <= 0 || len(users) == 0 { - return fmt.Errorf("invalid parameters: nodeId=%d, users=%v", nodeId, users) - } - // Organize data - data := make(map[int64][]string) - for _, user := range users { - data[user.SID] = append(data[user.SID], user.IP) - } - - value, err := json.Marshal(data) - if err != nil { - return fmt.Errorf("failed to marshal data: %w", err) - } - - c.Set(ctx, fmt.Sprintf(NodeOnlineUserCacheKey, nodeId), value, time.Minute*5) - return nil -} - -// GetNodeOnlineUser gets node's online users and IPs -func (c *NodeCacheClient) GetNodeOnlineUser(ctx context.Context, nodeId int64) (map[int64][]string, error) { - if nodeId <= 0 { - return nil, fmt.Errorf("invalid parameters: nodeId=%d", nodeId) - } - value, err := c.Get(ctx, fmt.Sprintf(NodeOnlineUserCacheKey, nodeId)).Result() - if err != nil { - return nil, fmt.Errorf("failed to get node online user: %w", err) - } - var data map[int64][]string - if err := json.Unmarshal([]byte(value), &data); err != nil { - return nil, fmt.Errorf("failed to unmarshal data: %w", err) - } - return data, nil -} - -// AddUserTodayTraffic Add user's today traffic -func (c *NodeCacheClient) AddUserTodayTraffic(ctx context.Context, uid int64, upload, download int64) error { - if uid <= 0 || upload <= 0 { - return fmt.Errorf("invalid parameters: uid=%d, upload=%d", uid, upload) - } - pipe := c.Pipeline() - // User's today upload traffic - pipe.HIncrBy(ctx, UserTodayUploadTrafficCacheKey, fmt.Sprintf("%d", uid), upload) - // User's today download traffic - pipe.HIncrBy(ctx, UserTodayDownloadTrafficCacheKey, fmt.Sprintf("%d", uid), download) - // User's today total traffic - pipe.HIncrBy(ctx, UserTodayTotalTrafficCacheKey, fmt.Sprintf("%d", uid), upload+download) - // User's today traffic ranking - pipe.ZIncrBy(ctx, UserTodayUploadTrafficRankKey, float64(upload), fmt.Sprintf("%d", uid)) - pipe.ZIncrBy(ctx, UserTodayDownloadTrafficRankKey, float64(download), fmt.Sprintf("%d", uid)) - pipe.ZIncrBy(ctx, UserTodayTotalTrafficRankKey, float64(upload+download), fmt.Sprintf("%d", uid)) - - // All node upload traffic - pipe.IncrBy(ctx, AllNodeUploadTrafficCacheKey, upload) - // All node download traffic - pipe.IncrBy(ctx, AllNodeDownloadTrafficCacheKey, download) - // Execute commands - _, err := pipe.Exec(ctx) - if err != nil { - return fmt.Errorf("failed to add user today upload traffic: %w", err) - } - return nil -} - -// AddNodeTodayTraffic Add node's today traffic -func (c *NodeCacheClient) AddNodeTodayTraffic(ctx context.Context, nodeId int64, userTraffic []UserTraffic) error { - if nodeId <= 0 || len(userTraffic) == 0 { - return fmt.Errorf("invalid parameters: nodeId=%d, userTraffic=%v", nodeId, userTraffic) - } - pipe := c.Pipeline() - upload, download, total := c.calculateTraffic(userTraffic) - pipe.HIncrBy(ctx, NodeTodayUploadTrafficCacheKey, fmt.Sprintf("%d", nodeId), upload) - pipe.HIncrBy(ctx, NodeTodayDownloadTrafficCacheKey, fmt.Sprintf("%d", nodeId), download) - pipe.HIncrBy(ctx, NodeTodayTotalTrafficCacheKey, fmt.Sprintf("%d", nodeId), total) - pipe.ZIncrBy(ctx, NodeTodayUploadTrafficRankKey, float64(upload), fmt.Sprintf("%d", nodeId)) - pipe.ZIncrBy(ctx, NodeTodayDownloadTrafficRankKey, float64(download), fmt.Sprintf("%d", nodeId)) - pipe.ZIncrBy(ctx, NodeTodayTotalTrafficRankKey, float64(total), fmt.Sprintf("%d", nodeId)) - // Execute commands - _, err := pipe.Exec(ctx) - if err != nil { - return fmt.Errorf("failed to add node today upload traffic: %w", err) - } - return nil -} - -// Get user's traffic data -func (c *NodeCacheClient) getUserTrafficData(ctx context.Context, uid int64) (upload, download int64, err error) { - upload, err = c.HGet(ctx, UserTodayUploadTrafficCacheKey, fmt.Sprintf("%d", uid)).Int64() - if err != nil { - return 0, 0, fmt.Errorf("failed to get user today upload traffic: %w", err) - } - download, err = c.HGet(ctx, UserTodayDownloadTrafficCacheKey, fmt.Sprintf("%d", uid)).Int64() - if err != nil { - return 0, 0, fmt.Errorf("failed to get user today download traffic: %w", err) - } - return upload, download, nil -} - -// Get node's traffic data -func (c *NodeCacheClient) getNodeTrafficData(ctx context.Context, nodeId int64) (upload, download int64, err error) { - upload, err = c.HGet(ctx, NodeTodayUploadTrafficCacheKey, fmt.Sprintf("%d", nodeId)).Int64() - if err != nil { - return 0, 0, fmt.Errorf("failed to get node today upload traffic: %w", err) - } - download, err = c.HGet(ctx, NodeTodayDownloadTrafficCacheKey, fmt.Sprintf("%d", nodeId)).Int64() - if err != nil { - return 0, 0, fmt.Errorf("failed to get node today download traffic: %w", err) - } - return upload, download, nil -} - -// Parse ID -func (c *NodeCacheClient) parseID(member interface{}, idType string) (int64, error) { - id, err := strconv.ParseInt(member.(string), 10, 64) - if err != nil { - return 0, fmt.Errorf("failed to parse %s id %v: %w", idType, member, err) - } - return id, nil -} - -// GetUserTodayTotalTrafficRank Get user's today total traffic ranking top N -func (c *NodeCacheClient) GetUserTodayTotalTrafficRank(ctx context.Context, n int64) ([]UserTodayTrafficRank, error) { - if n <= 0 { - return nil, fmt.Errorf("invalid parameters: n=%d", n) - } - data, err := c.ZRevRangeWithScores(ctx, UserTodayTotalTrafficRankKey, 0, n-1).Result() - if err != nil { - return nil, fmt.Errorf("failed to get user today total traffic rank: %w", err) - } - users := make([]UserTodayTrafficRank, 0, len(data)) - for _, user := range data { - uid, err := c.parseID(user.Member, "user") - if err != nil { - logger.Errorf("%v", err) - continue - } - upload, download, err := c.getUserTrafficData(ctx, uid) - if err != nil { - logger.Errorf("%v", err) - continue - } - users = append(users, UserTodayTrafficRank{ - SID: uid, - Upload: upload, - Download: download, - Total: int64(user.Score), - }) - } - return users, nil -} - -// GetNodeTodayTotalTrafficRank Get node's today total traffic ranking top N -func (c *NodeCacheClient) GetNodeTodayTotalTrafficRank(ctx context.Context, n int64) ([]NodeTodayTrafficRank, error) { - if n <= 0 { - return nil, fmt.Errorf("invalid parameters: n=%d", n) - } - data, err := c.ZRevRangeWithScores(ctx, NodeTodayTotalTrafficRankKey, 0, n-1).Result() - if err != nil { - return nil, fmt.Errorf("failed to get node today total traffic rank: %w", err) - } - nodes := make([]NodeTodayTrafficRank, 0, len(data)) - for _, node := range data { - nodeId, err := c.parseID(node.Member, "node") - if err != nil { - logger.Errorf("%v", err) - continue - } - upload, download, err := c.getNodeTrafficData(ctx, nodeId) - if err != nil { - logger.Errorf("%v", err) - continue - } - nodes = append(nodes, NodeTodayTrafficRank{ - ID: nodeId, - Upload: upload, - Download: download, - Total: int64(node.Score), - }) - } - return nodes, nil -} - -// GetUserTodayUploadTrafficRank Get user's today upload traffic ranking top N -func (c *NodeCacheClient) GetUserTodayUploadTrafficRank(ctx context.Context, n int64) ([]UserTodayTrafficRank, error) { - if n <= 0 { - return nil, fmt.Errorf("invalid parameters: n=%d", n) - } - data, err := c.ZRevRangeWithScores(ctx, UserTodayUploadTrafficRankKey, 0, n-1).Result() - if err != nil { - return nil, fmt.Errorf("failed to get user today upload traffic rank: %w", err) - } - users := make([]UserTodayTrafficRank, 0, len(data)) - for _, user := range data { - uid, err := c.parseID(user.Member, "user") - if err != nil { - logger.Errorf("%v", err) - continue - } - upload, download, err := c.getUserTrafficData(ctx, uid) - if err != nil { - logger.Errorf("%v", err) - continue - } - users = append(users, UserTodayTrafficRank{ - SID: uid, - Upload: upload, - Download: download, - Total: int64(user.Score), - }) - } - return users, nil -} - -// GetUserTodayDownloadTrafficRank Get user's today download traffic ranking top N -func (c *NodeCacheClient) GetUserTodayDownloadTrafficRank(ctx context.Context, n int64) ([]UserTodayTrafficRank, error) { - if n <= 0 { - return nil, fmt.Errorf("invalid parameters: n=%d", n) - } - data, err := c.ZRevRangeWithScores(ctx, UserTodayDownloadTrafficRankKey, 0, n-1).Result() - if err != nil { - return nil, fmt.Errorf("failed to get user today download traffic rank: %w", err) - } - users := make([]UserTodayTrafficRank, 0, len(data)) - for _, user := range data { - uid, err := c.parseID(user.Member, "user") - if err != nil { - logger.Errorf("%v", err) - continue - } - upload, download, err := c.getUserTrafficData(ctx, uid) - if err != nil { - logger.Errorf("%v", err) - continue - } - users = append(users, UserTodayTrafficRank{ - SID: uid, - Upload: upload, - Download: download, - Total: int64(user.Score), - }) - } - return users, nil -} - -// GetNodeTodayUploadTrafficRank Get node's today upload traffic ranking top N -func (c *NodeCacheClient) GetNodeTodayUploadTrafficRank(ctx context.Context, n int64) ([]NodeTodayTrafficRank, error) { - if n <= 0 { - return nil, fmt.Errorf("invalid parameters: n=%d", n) - } - data, err := c.ZRevRangeWithScores(ctx, NodeTodayUploadTrafficRankKey, 0, n-1).Result() - if err != nil { - return nil, fmt.Errorf("failed to get node today upload traffic rank: %w", err) - } - nodes := make([]NodeTodayTrafficRank, 0, len(data)) - for _, node := range data { - nodeId, err := c.parseID(node.Member, "node") - if err != nil { - logger.Errorf("%v", err) - continue - } - upload, download, err := c.getNodeTrafficData(ctx, nodeId) - if err != nil { - logger.Errorf("%v", err) - continue - } - nodes = append(nodes, NodeTodayTrafficRank{ - ID: nodeId, - Upload: upload, - Download: download, - Total: int64(node.Score), - }) - } - return nodes, nil -} - -// GetNodeTodayDownloadTrafficRank Get node's today download traffic ranking top N -func (c *NodeCacheClient) GetNodeTodayDownloadTrafficRank(ctx context.Context, n int64) ([]NodeTodayTrafficRank, error) { - if n <= 0 { - return nil, fmt.Errorf("invalid parameters: n=%d", n) - } - data, err := c.ZRevRangeWithScores(ctx, NodeTodayDownloadTrafficRankKey, 0, n-1).Result() - if err != nil { - return nil, fmt.Errorf("failed to get node today download traffic rank: %w", err) - } - nodes := make([]NodeTodayTrafficRank, 0, len(data)) - for _, node := range data { - nodeId, err := c.parseID(node.Member, "node") - if err != nil { - logger.Errorf("%v", err) - continue - } - upload, download, err := c.getNodeTrafficData(ctx, nodeId) - if err != nil { - logger.Errorf("%v", err) - continue - } - nodes = append(nodes, NodeTodayTrafficRank{ - ID: nodeId, - Upload: upload, - Download: download, - Total: int64(node.Score), - }) - } - return nodes, nil -} - -// ResetTodayTrafficData Reset today's traffic data -func (c *NodeCacheClient) ResetTodayTrafficData(ctx context.Context) error { - c.resetMutex.Lock() - defer c.resetMutex.Unlock() - pipe := c.Pipeline() - pipe.Del(ctx, UserTodayUploadTrafficCacheKey) - pipe.Del(ctx, UserTodayDownloadTrafficCacheKey) - pipe.Del(ctx, UserTodayTotalTrafficCacheKey) - pipe.Del(ctx, NodeTodayUploadTrafficCacheKey) - pipe.Del(ctx, NodeTodayDownloadTrafficCacheKey) - pipe.Del(ctx, NodeTodayTotalTrafficCacheKey) - pipe.Del(ctx, UserTodayUploadTrafficRankKey) - pipe.Del(ctx, UserTodayDownloadTrafficRankKey) - pipe.Del(ctx, UserTodayTotalTrafficRankKey) - pipe.Del(ctx, NodeTodayUploadTrafficRankKey) - pipe.Del(ctx, NodeTodayDownloadTrafficRankKey) - pipe.Del(ctx, NodeTodayTotalTrafficRankKey) - pipe.Del(ctx, AllNodeDownloadTrafficCacheKey) - pipe.Del(ctx, AllNodeUploadTrafficCacheKey) - _, err := pipe.Exec(ctx) - if err != nil { - return fmt.Errorf("failed to reset today traffic data: %w", err) - } - return nil -} - -// Calculate traffic -func (c *NodeCacheClient) calculateTraffic(data []UserTraffic) (upload, download, total int64) { - for _, userTraffic := range data { - upload += userTraffic.Upload - download += userTraffic.Download - total += userTraffic.Upload + userTraffic.Download - } - return upload, download, total -} - -// GetAllNodeOnlineUser Get all node online user -func (c *NodeCacheClient) GetAllNodeOnlineUser(ctx context.Context) ([]string, error) { - users, err := c.ZRevRange(ctx, AllNodeOnlineUserCacheKey, 0, -1).Result() - if err != nil { - return nil, fmt.Errorf("failed to get all node online user: %w", err) - } - return users, nil -} - -// UpdateNodeStatus Update node status -func (c *NodeCacheClient) UpdateNodeStatus(ctx context.Context, nodeId int64, status NodeStatus) error { - // 参数验证 - if nodeId <= 0 { - return fmt.Errorf("invalid node id: %d", nodeId) - } - - // 验证状态数据 - if status.UpdatedAt <= 0 { - return fmt.Errorf("invalid status data: updated_at=%d", status.UpdatedAt) - } - - // 序列化状态数据 - value, err := json.Marshal(status) - if err != nil { - return fmt.Errorf("failed to marshal node status: %w", err) - } - - // 使用 Pipeline 优化性能 - pipe := c.Pipeline() - - // 设置状态数据 - pipe.Set(ctx, fmt.Sprintf(NodeStatusCacheKey, nodeId), value, time.Minute*5) - - // 执行命令 - _, err = pipe.Exec(ctx) - if err != nil { - return fmt.Errorf("failed to update node status: %w", err) - } - - return nil -} - -// GetNodeStatus Get node status -func (c *NodeCacheClient) GetNodeStatus(ctx context.Context, nodeId int64) (NodeStatus, error) { - status, err := c.Get(ctx, fmt.Sprintf(NodeStatusCacheKey, nodeId)).Result() - if err != nil { - return NodeStatus{}, fmt.Errorf("failed to get node status: %w", err) - } - var nodeStatus NodeStatus - if err := json.Unmarshal([]byte(status), &nodeStatus); err != nil { - return NodeStatus{}, fmt.Errorf("failed to unmarshal node status: %w", err) - } - return nodeStatus, nil -} - -// GetOnlineNodeStatusCount Get Online Node Status Count -func (c *NodeCacheClient) GetOnlineNodeStatusCount(ctx context.Context) (int64, error) { - // 获取所有节点Key - keys, err := c.Keys(ctx, "node:status:*").Result() - if err != nil { - return 0, fmt.Errorf("failed to get all node status keys: %w", err) - } - var count int64 - for _, key := range keys { - status, err := c.Get(ctx, key).Result() - if err != nil { - logger.Errorf("failed to get node status: %v", err.Error()) - continue - } - if status != "" { - count++ - } - } - return count, nil -} - -// GetAllNodeUploadTraffic Get all node upload traffic -func (c *NodeCacheClient) GetAllNodeUploadTraffic(ctx context.Context) (int64, error) { - upload, err := c.Get(ctx, AllNodeUploadTrafficCacheKey).Int64() - if err != nil { - return 0, fmt.Errorf("failed to get all node upload traffic: %w", err) - } - return upload, nil -} - -// GetAllNodeDownloadTraffic Get all node download traffic -func (c *NodeCacheClient) GetAllNodeDownloadTraffic(ctx context.Context) (int64, error) { - download, err := c.Get(ctx, AllNodeDownloadTrafficCacheKey).Int64() - if err != nil { - return 0, fmt.Errorf("failed to get all node download traffic: %w", err) - } - return download, nil -} - -// UpdateYesterdayNodeTotalTrafficRank Update yesterday node total traffic rank -func (c *NodeCacheClient) UpdateYesterdayNodeTotalTrafficRank(ctx context.Context, nodes []NodeTodayTrafficRank) error { - expireAt := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), 0, 0, 0, 0, time.Local).Add(time.Hour * 24) - t := time.Until(expireAt) - pipe := c.Pipeline() - value, _ := json.Marshal(nodes) - pipe.Set(ctx, YesterdayNodeTotalTrafficRank, value, t) - _, err := pipe.Exec(ctx) - if err != nil { - return fmt.Errorf("failed to update yesterday node total traffic rank: %w", err) - } - return nil -} - -// UpdateYesterdayUserTotalTrafficRank Update yesterday user total traffic rank -func (c *NodeCacheClient) UpdateYesterdayUserTotalTrafficRank(ctx context.Context, users []UserTodayTrafficRank) error { - expireAt := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), 0, 0, 0, 0, time.Local).Add(time.Hour * 24) - t := time.Until(expireAt) - pipe := c.Pipeline() - value, _ := json.Marshal(users) - pipe.Set(ctx, YesterdayUserTotalTrafficRank, value, t) - _, err := pipe.Exec(ctx) - if err != nil { - return fmt.Errorf("failed to update yesterday user total traffic rank: %w", err) - } - return nil -} - -// GetYesterdayNodeTotalTrafficRank Get yesterday node total traffic rank -func (c *NodeCacheClient) GetYesterdayNodeTotalTrafficRank(ctx context.Context) ([]NodeTodayTrafficRank, error) { - value, err := c.Get(ctx, YesterdayNodeTotalTrafficRank).Result() - if err != nil { - return nil, fmt.Errorf("failed to get yesterday node total traffic rank: %w", err) - } - var nodes []NodeTodayTrafficRank - if err := json.Unmarshal([]byte(value), &nodes); err != nil { - return nil, fmt.Errorf("failed to unmarshal yesterday node total traffic rank: %w", err) - } - return nodes, nil -} - -// GetYesterdayUserTotalTrafficRank Get yesterday user total traffic rank -func (c *NodeCacheClient) GetYesterdayUserTotalTrafficRank(ctx context.Context) ([]UserTodayTrafficRank, error) { - value, err := c.Get(ctx, YesterdayUserTotalTrafficRank).Result() - if err != nil { - return nil, fmt.Errorf("failed to get yesterday user total traffic rank: %w", err) - } - var users []UserTodayTrafficRank - if err := json.Unmarshal([]byte(value), &users); err != nil { - return nil, fmt.Errorf("failed to unmarshal yesterday user total traffic rank: %w", err) - } - return users, nil -} diff --git a/internal/model/cache/node_test.go b/internal/model/cache/node_test.go deleted file mode 100644 index b7660ab..0000000 --- a/internal/model/cache/node_test.go +++ /dev/null @@ -1,575 +0,0 @@ -package cache - -import ( - "context" - "encoding/json" - "fmt" - "testing" - "time" - - "github.com/alicebob/miniredis/v2" - "github.com/redis/go-redis/v9" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -// Create a test Redis client -func newTestRedisClient(t *testing.T) *redis.Client { - mr, err := miniredis.Run() - require.NoError(t, err) - - client := redis.NewClient(&redis.Options{ - Addr: mr.Addr(), - }) - require.NoError(t, client.Ping(context.Background()).Err()) - return client -} - -// Clean up test data -func cleanupTestData(t *testing.T, client *redis.Client) { - ctx := context.Background() - keys := []string{ - UserTodayUploadTrafficCacheKey, - UserTodayDownloadTrafficCacheKey, - UserTodayTotalTrafficCacheKey, - NodeTodayUploadTrafficCacheKey, - NodeTodayDownloadTrafficCacheKey, - NodeTodayTotalTrafficCacheKey, - UserTodayUploadTrafficRankKey, - UserTodayDownloadTrafficRankKey, - UserTodayTotalTrafficRankKey, - NodeTodayUploadTrafficRankKey, - NodeTodayDownloadTrafficRankKey, - NodeTodayTotalTrafficRankKey, - } - - // Clean up all cache keys - for _, key := range keys { - require.NoError(t, client.Del(ctx, key).Err()) - } - - // Clean up user online IP cache - for uid := int64(1); uid <= 3; uid++ { - require.NoError(t, client.Del(ctx, fmt.Sprintf(UserOnlineIpCacheKey, uid)).Err()) - } - - // Clean up node online user cache - for nodeId := int64(1); nodeId <= 3; nodeId++ { - require.NoError(t, client.Del(ctx, fmt.Sprintf(NodeOnlineUserCacheKey, nodeId)).Err()) - } -} - -func TestNodeCacheClient_AddUserTodayTraffic(t *testing.T) { - client := newTestRedisClient(t) - defer cleanupTestData(t, client) - - cache := NewNodeCacheClient(client) - ctx := context.Background() - - tests := []struct { - name string - uid int64 - upload int64 - download int64 - wantErr bool - }{ - { - name: "Add traffic normally", - uid: 1, - upload: 100, - download: 200, - wantErr: false, - }, - { - name: "Invalid SID", - uid: 0, - upload: 100, - download: 200, - wantErr: true, - }, - { - name: "Invalid upload traffic", - uid: 1, - upload: 0, - download: 200, - wantErr: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := cache.AddUserTodayTraffic(ctx, tt.uid, tt.upload, tt.download) - if tt.wantErr { - assert.Error(t, err) - return - } - assert.NoError(t, err) - - // Verify data is added correctly - upload, err := client.HGet(ctx, UserTodayUploadTrafficCacheKey, "1").Int64() - assert.NoError(t, err) - assert.Equal(t, tt.upload, upload) - - download, err := client.HGet(ctx, UserTodayDownloadTrafficCacheKey, "1").Int64() - assert.NoError(t, err) - assert.Equal(t, tt.download, download) - }) - } -} - -func TestNodeCacheClient_AddNodeTodayTraffic(t *testing.T) { - client := newTestRedisClient(t) - defer cleanupTestData(t, client) - - cache := NewNodeCacheClient(client) - ctx := context.Background() - - tests := []struct { - name string - nodeId int64 - userTraffic []UserTraffic - wantErr bool - }{ - { - name: "Add node traffic normally", - nodeId: 1, - userTraffic: []UserTraffic{ - {UID: 1, Upload: 100, Download: 200}, - {UID: 2, Upload: 300, Download: 400}, - }, - wantErr: false, - }, - { - name: "Invalid node ID", - nodeId: 0, - userTraffic: []UserTraffic{ - {UID: 1, Upload: 100, Download: 200}, - }, - wantErr: true, - }, - { - name: "Empty user traffic data", - nodeId: 1, - userTraffic: []UserTraffic{}, - wantErr: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := cache.AddNodeTodayTraffic(ctx, tt.nodeId, tt.userTraffic) - if tt.wantErr { - assert.Error(t, err) - return - } - assert.NoError(t, err) - - // Verify data is added correctly - upload, err := client.HGet(ctx, NodeTodayUploadTrafficCacheKey, "1").Int64() - assert.NoError(t, err) - assert.Equal(t, int64(400), upload) // 100 + 300 - - download, err := client.HGet(ctx, NodeTodayDownloadTrafficCacheKey, "1").Int64() - assert.NoError(t, err) - assert.Equal(t, int64(600), download) // 200 + 400 - }) - } -} - -func TestNodeCacheClient_GetUserTodayTrafficRank(t *testing.T) { - client := newTestRedisClient(t) - defer cleanupTestData(t, client) - - cache := NewNodeCacheClient(client) - ctx := context.Background() - - // Prepare test data - testData := []struct { - uid int64 - upload int64 - download int64 - }{ - {1, 100, 200}, - {2, 300, 400}, - {3, 500, 600}, - } - - for _, data := range testData { - err := cache.AddUserTodayTraffic(ctx, data.uid, data.upload, data.download) - require.NoError(t, err) - } - - tests := []struct { - name string - n int64 - wantErr bool - }{ - { - name: "Get top 2 ranks", - n: 2, - wantErr: false, - }, - { - name: "Get all ranks", - n: 3, - wantErr: false, - }, - { - name: "Invalid N value", - n: 0, - wantErr: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ranks, err := cache.GetUserTodayTotalTrafficRank(ctx, tt.n) - if tt.wantErr { - assert.Error(t, err) - return - } - assert.NoError(t, err) - assert.Len(t, ranks, int(tt.n)) - - // Verify sorting is correct - for i := 1; i < len(ranks); i++ { - assert.GreaterOrEqual(t, ranks[i-1].Total, ranks[i].Total) - } - }) - } -} - -func TestNodeCacheClient_ResetTodayTrafficData(t *testing.T) { - client := newTestRedisClient(t) - defer cleanupTestData(t, client) - - cache := NewNodeCacheClient(client) - ctx := context.Background() - - // Prepare test data - err := cache.AddUserTodayTraffic(ctx, 1, 100, 200) - require.NoError(t, err) - err = cache.AddNodeTodayTraffic(ctx, 1, []UserTraffic{{UID: 1, Upload: 100, Download: 200}}) - require.NoError(t, err) - - // Test reset functionality - err = cache.ResetTodayTrafficData(ctx) - assert.NoError(t, err) - - // Verify data is cleared - keys := []string{ - UserTodayUploadTrafficCacheKey, - UserTodayDownloadTrafficCacheKey, - UserTodayTotalTrafficCacheKey, - NodeTodayUploadTrafficCacheKey, - NodeTodayDownloadTrafficCacheKey, - NodeTodayTotalTrafficCacheKey, - } - - for _, key := range keys { - exists, err := client.Exists(ctx, key).Result() - assert.NoError(t, err) - assert.Equal(t, int64(0), exists) - } -} - -func TestNodeCacheClient_GetNodeTodayTrafficRank(t *testing.T) { - client := newTestRedisClient(t) - defer cleanupTestData(t, client) - - cache := NewNodeCacheClient(client) - ctx := context.Background() - - // Prepare test data - testData := []struct { - nodeId int64 - traffic []UserTraffic - }{ - {1, []UserTraffic{{UID: 1, Upload: 100, Download: 200}}}, - {2, []UserTraffic{{UID: 2, Upload: 300, Download: 400}}}, - {3, []UserTraffic{{UID: 3, Upload: 500, Download: 600}}}, - } - - for _, data := range testData { - err := cache.AddNodeTodayTraffic(ctx, data.nodeId, data.traffic) - require.NoError(t, err) - } - - tests := []struct { - name string - n int64 - wantErr bool - }{ - { - name: "Get top 2 ranks", - n: 2, - wantErr: false, - }, - { - name: "Get all ranks", - n: 3, - wantErr: false, - }, - { - name: "Invalid N value", - n: 0, - wantErr: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ranks, err := cache.GetNodeTodayTotalTrafficRank(ctx, tt.n) - if tt.wantErr { - assert.Error(t, err) - return - } - assert.NoError(t, err) - assert.Len(t, ranks, int(tt.n)) - - // Verify sorting is correct - for i := 1; i < len(ranks); i++ { - assert.GreaterOrEqual(t, ranks[i-1].Total, ranks[i].Total) - } - }) - } -} - -func TestNodeCacheClient_AddNodeOnlineUser(t *testing.T) { - client := newTestRedisClient(t) - defer cleanupTestData(t, client) - - cache := NewNodeCacheClient(client) - ctx := context.Background() - - tests := []struct { - name string - nodeId int64 - users []NodeOnlineUser - wantErr bool - }{ - { - name: "Add online users normally", - nodeId: 1, - users: []NodeOnlineUser{ - {SID: 1, IP: "192.168.1.1"}, - {SID: 2, IP: "192.168.1.2"}, - }, - wantErr: false, - }, - { - name: "Invalid node ID", - nodeId: 0, - users: []NodeOnlineUser{ - {SID: 1, IP: "192.168.1.1"}, - }, - wantErr: false, - }, - { - name: "Empty user list", - nodeId: 1, - users: []NodeOnlineUser{}, - wantErr: false, - }, - { - name: "Add duplicate user IP", - nodeId: 1, - users: []NodeOnlineUser{ - {SID: 1, IP: "192.168.1.1"}, - {SID: 1, IP: "192.168.1.1"}, - }, - wantErr: false, - }, - { - name: "Multiple IPs for same user", - nodeId: 1, - users: []NodeOnlineUser{ - {SID: 1, IP: "192.168.1.1"}, - {SID: 1, IP: "192.168.1.2"}, - }, - wantErr: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := cache.AddOnlineUserIP(ctx, tt.users) - if tt.wantErr { - assert.Error(t, err) - return - } - assert.NoError(t, err) - - // Verify data is added correctly - for _, user := range tt.users { - // Get user online IPs - ips, err := cache.GetUserOnlineIp(ctx, user.SID) - assert.NoError(t, err) - assert.Contains(t, ips, user.IP) - - // Verify score is within valid range (current time to 5 minutes later) - score, err := client.ZScore(ctx, fmt.Sprintf(UserOnlineIpCacheKey, user.SID), user.IP).Result() - assert.NoError(t, err) - now := time.Now().Unix() - assert.GreaterOrEqual(t, score, float64(now)) - assert.LessOrEqual(t, score, float64(now+300)) // 5 minutes = 300 seconds - - // Verify key exists - exists, err := client.Exists(ctx, fmt.Sprintf(UserOnlineIpCacheKey, user.SID)).Result() - assert.NoError(t, err) - assert.Equal(t, int64(1), exists) - } - }) - } -} - -func TestNodeCacheClient_GetUserOnlineIp(t *testing.T) { - client := newTestRedisClient(t) - defer cleanupTestData(t, client) - - cache := NewNodeCacheClient(client) - ctx := context.Background() - - // Prepare test data - testData := []struct { - nodeId int64 - users []NodeOnlineUser - }{ - { - nodeId: 1, - users: []NodeOnlineUser{ - {SID: 1, IP: "192.168.1.1"}, - {SID: 1, IP: "192.168.1.2"}, - {SID: 2, IP: "192.168.1.3"}, - }, - }, - } - - // Add test data - for _, data := range testData { - err := cache.AddOnlineUserIP(ctx, data.users) - require.NoError(t, err) - } - - tests := []struct { - name string - uid int64 - wantErr bool - wantIPs []string - }{ - { - name: "Get existing user IPs", - uid: 1, - wantErr: false, - wantIPs: []string{"192.168.1.1", "192.168.1.2"}, - }, - { - name: "Get another user's IPs", - uid: 2, - wantErr: false, - wantIPs: []string{"192.168.1.3"}, - }, - { - name: "Get non-existent user IPs", - uid: 3, - wantErr: false, - wantIPs: []string{}, - }, - { - name: "Invalid user ID", - uid: 0, - wantErr: true, - }, - { - name: "Expired IPs should not be returned", - uid: 1, - wantErr: false, - wantIPs: []string{"192.168.1.1", "192.168.1.2"}, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ips, err := cache.GetUserOnlineIp(ctx, tt.uid) - if tt.wantErr { - assert.Error(t, err) - return - } - assert.NoError(t, err) - assert.ElementsMatch(t, tt.wantIPs, ips) - - // Verify all returned IPs are valid - for _, ip := range ips { - score, err := client.ZScore(ctx, fmt.Sprintf(UserOnlineIpCacheKey, tt.uid), ip).Result() - assert.NoError(t, err) - now := time.Now().Unix() - assert.GreaterOrEqual(t, score, float64(now)) - } - }) - } -} - -func TestNodeCacheClient_UpdateNodeOnlineUser(t *testing.T) { - client := newTestRedisClient(t) - defer cleanupTestData(t, client) - - cache := NewNodeCacheClient(client) - ctx := context.Background() - - tests := []struct { - name string - nodeId int64 - users []NodeOnlineUser - wantErr bool - }{ - { - name: "Update online users normally", - nodeId: 1, - users: []NodeOnlineUser{ - {SID: 1, IP: "192.168.1.1"}, - {SID: 2, IP: "192.168.1.2"}, - }, - wantErr: false, - }, - { - name: "Invalid node ID", - nodeId: 0, - users: []NodeOnlineUser{ - {SID: 1, IP: "192.168.1.1"}, - }, - wantErr: true, - }, - { - name: "Empty user list", - nodeId: 1, - users: []NodeOnlineUser{}, - wantErr: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := cache.UpdateNodeOnlineUser(ctx, tt.nodeId, tt.users) - if tt.wantErr { - assert.Error(t, err) - return - } - assert.NoError(t, err) - - // Verify data is updated correctly - data, err := client.Get(ctx, fmt.Sprintf(NodeOnlineUserCacheKey, tt.nodeId)).Result() - assert.NoError(t, err) - - var result map[int64][]string - err = json.Unmarshal([]byte(data), &result) - assert.NoError(t, err) - - // Verify data content - for _, user := range tt.users { - ips, exists := result[user.SID] - assert.True(t, exists) - assert.Contains(t, ips, user.IP) - } - }) - } -} diff --git a/internal/model/cache/types.go b/internal/model/cache/types.go deleted file mode 100644 index 89b6144..0000000 --- a/internal/model/cache/types.go +++ /dev/null @@ -1,34 +0,0 @@ -package cache - -type NodeOnlineUser struct { - SID int64 - IP string -} - -type NodeTodayTrafficRank struct { - ID int64 - Name string - Upload int64 - Download int64 - Total int64 -} - -type UserTodayTrafficRank struct { - SID int64 - Upload int64 - Download int64 - Total int64 -} - -type UserTraffic struct { - UID int64 - Upload int64 - Download int64 -} - -type NodeStatus struct { - Cpu float64 - Mem float64 - Disk float64 - UpdatedAt int64 -} diff --git a/internal/model/client/application.go b/internal/model/client/application.go index 2bc9a6e..ff121d0 100644 --- a/internal/model/client/application.go +++ b/internal/model/client/application.go @@ -6,7 +6,7 @@ import ( ) type SubscribeApplication struct { - Id int64 `gorm:"primary_key"` + Id int64 `gorm:"primaryKey"` Name string `gorm:"type:varchar(255);default:'';not null;comment:Application Name"` Icon string `gorm:"type:MEDIUMTEXT;default:null;comment:Application Icon"` Description string `gorm:"type:varchar(255);default:null;comment:Application Description"` diff --git a/internal/model/client/default.go b/internal/model/client/default.go index 45f7883..c52108f 100644 --- a/internal/model/client/default.go +++ b/internal/model/client/default.go @@ -25,12 +25,12 @@ type ( func NewSubscribeApplicationModel(db *gorm.DB) Model { return &DefaultSubscribeApplicationModel{ - DB: db.Model(&SubscribeApplication{}), + DB: db, } } func (m *DefaultSubscribeApplicationModel) Insert(ctx context.Context, data *SubscribeApplication) error { - if err := m.WithContext(ctx).Create(data).Error; err != nil { + if err := m.WithContext(ctx).Model(&SubscribeApplication{}).Create(data).Error; err != nil { return err } return nil @@ -38,7 +38,7 @@ func (m *DefaultSubscribeApplicationModel) Insert(ctx context.Context, data *Sub func (m *DefaultSubscribeApplicationModel) FindOne(ctx context.Context, id int64) (*SubscribeApplication, error) { var resp SubscribeApplication - if err := m.WithContext(ctx).Where("id = ?", id).First(&resp).Error; err != nil { + if err := m.WithContext(ctx).Model(&SubscribeApplication{}).Where("id = ?", id).First(&resp).Error; err != nil { return nil, err } return &resp, nil @@ -48,14 +48,14 @@ func (m *DefaultSubscribeApplicationModel) Update(ctx context.Context, data *Sub if _, err := m.FindOne(ctx, data.Id); err != nil { return err } - if err := m.WithContext(ctx).Save(data).Error; err != nil { + if err := m.WithContext(ctx).Model(&SubscribeApplication{}).Where("`id` = ?", data.Id).Save(data).Error; err != nil { return err } return nil } func (m *DefaultSubscribeApplicationModel) Delete(ctx context.Context, id int64) error { - if err := m.WithContext(ctx).Delete(&SubscribeApplication{}, id).Error; err != nil { + if err := m.WithContext(ctx).Model(&SubscribeApplication{}).Where("`id` = ?", id).Delete(&SubscribeApplication{}).Error; err != nil { return err } return nil diff --git a/internal/model/log/default.go b/internal/model/log/default.go index 5b8d731..242891a 100644 --- a/internal/model/log/default.go +++ b/internal/model/log/default.go @@ -6,74 +6,50 @@ import ( "gorm.io/gorm" ) -var _ Model = (*customLogModel)(nil) +var _ Model = (*customSystemLogModel)(nil) type ( Model interface { - messageLogModel + systemLogModel + customSystemLogLogicModel } - messageLogModel interface { - InsertMessageLog(ctx context.Context, data *MessageLog) error - FindOneMessageLog(ctx context.Context, id int64) (*MessageLog, error) - UpdateMessageLog(ctx context.Context, data *MessageLog) error - DeleteMessageLog(ctx context.Context, id int64) error - FindMessageLogList(ctx context.Context, page, size int, filter MessageLogFilterParams) (int64, []*MessageLog, error) + systemLogModel interface { + Insert(ctx context.Context, data *SystemLog) error + FindOne(ctx context.Context, id int64) (*SystemLog, error) + Update(ctx context.Context, data *SystemLog) error + Delete(ctx context.Context, id int64) error } - - customLogModel struct { + customSystemLogModel struct { *defaultLogModel } defaultLogModel struct { - Connection *gorm.DB + *gorm.DB } ) -func newLogModel(db *gorm.DB) *defaultLogModel { +func newSystemLogModel(db *gorm.DB) *defaultLogModel { return &defaultLogModel{ - Connection: db, + DB: db, } } -func (m *defaultLogModel) InsertMessageLog(ctx context.Context, data *MessageLog) error { - return m.Connection.WithContext(ctx).Create(&data).Error +func (m *defaultLogModel) Insert(ctx context.Context, data *SystemLog) error { + return m.WithContext(ctx).Create(data).Error } -func (m *defaultLogModel) FindOneMessageLog(ctx context.Context, id int64) (*MessageLog, error) { - var resp MessageLog - err := m.Connection.WithContext(ctx).Model(&MessageLog{}).Where("`id` = ?", id).First(&resp).Error - return &resp, err +func (m *defaultLogModel) FindOne(ctx context.Context, id int64) (*SystemLog, error) { + var log SystemLog + err := m.WithContext(ctx).Where("id = ?", id).First(&log).Error + if err != nil { + return nil, err + } + return &log, nil } -func (m *defaultLogModel) UpdateMessageLog(ctx context.Context, data *MessageLog) error { - return m.Connection.WithContext(ctx).Model(&MessageLog{}).Where("id = ?", data.Id).Updates(data).Error +func (m *defaultLogModel) Update(ctx context.Context, data *SystemLog) error { + return m.WithContext(ctx).Where("`id` = ?", data.Id).Save(data).Error } -func (m *defaultLogModel) DeleteMessageLog(ctx context.Context, id int64) error { - return m.Connection.WithContext(ctx).Model(&MessageLog{}).Where("id = ?", id).Delete(&MessageLog{}).Error -} - -func (m *defaultLogModel) FindMessageLogList(ctx context.Context, page, size int, filter MessageLogFilterParams) (int64, []*MessageLog, error) { - var list []*MessageLog - var total int64 - conn := m.Connection.WithContext(ctx).Model(&MessageLog{}) - if filter.Type != "" { - conn = conn.Where("`type` = ?", filter.Type) - } - if filter.Platform != "" { - conn = conn.Where("`platform` = ?", filter.Platform) - } - if filter.To != "" { - conn = conn.Where("`to` LIKE ?", "%"+filter.To+"%") - } - if filter.Subject != "" { - conn = conn.Where("`subject` LIKE ?", "%"+filter.Subject+"%") - } - if filter.Content != "" { - conn = conn.Where("`content` = ?", "%"+filter.Content+"%") - } - if filter.Status > 0 { - conn = conn.Where("`status` = ?", filter.Status) - } - err := conn.Count(&total).Offset((page - 1) * size).Limit(size).Find(&list).Error - return total, list, err +func (m *defaultLogModel) Delete(ctx context.Context, id int64) error { + return m.WithContext(ctx).Where("`id` = ?", id).Delete(&SystemLog{}).Error } diff --git a/internal/model/log/log.go b/internal/model/log/log.go index af66746..af3eb98 100644 --- a/internal/model/log/log.go +++ b/internal/model/log/log.go @@ -1,45 +1,424 @@ package log -import "time" - -type MessageType int - -const ( - Email MessageType = iota + 1 - Mobile +import ( + "encoding/json" + "time" ) -func (t MessageType) String() string { - switch t { - case Email: - return "email" - case Mobile: - return "mobile" - } - return "unknown" +type Type uint8 + +/* + +Log Types: + 1X Message Logs + 2X Subscription Logs + 3X User Logs + 4X Traffic Ranking Logs +*/ + +const ( + TypeEmailMessage Type = 10 // Message log + TypeMobileMessage Type = 11 // Mobile message log + TypeSubscribe Type = 20 // Subscription log + TypeSubscribeTraffic Type = 21 // Subscription traffic log + TypeServerTraffic Type = 22 // Server traffic log + TypeResetSubscribe Type = 23 // Reset subscription log + TypeLogin Type = 30 // Login log + TypeRegister Type = 31 // Registration log + TypeBalance Type = 32 // Balance log + TypeCommission Type = 33 // Commission log + TypeGift Type = 34 // Gift log + TypeUserTrafficRank Type = 40 // Top 10 User traffic rank log + TypeServerTrafficRank Type = 41 // Top 10 Server traffic rank log + TypeTrafficStat Type = 42 // Daily traffic statistics log +) +const ( + ResetSubscribeTypeAuto uint16 = 231 // Auto reset + ResetSubscribeTypeAdvance uint16 = 232 // Advance reset + ResetSubscribeTypePaid uint16 = 233 // Paid reset + ResetSubscribeTypeQuota uint16 = 234 // Quota reset + BalanceTypeRecharge uint16 = 321 // Recharge + BalanceTypeWithdraw uint16 = 322 // Withdraw + BalanceTypePayment uint16 = 323 // Payment + BalanceTypeRefund uint16 = 324 // Refund + BalanceTypeAdjust uint16 = 326 // Admin Adjust + BalanceTypeReward uint16 = 325 // Reward + CommissionTypePurchase uint16 = 331 // Purchase + CommissionTypeRenewal uint16 = 332 // Renewal + CommissionTypeRefund uint16 = 333 // Refund + commissionTypeWithdraw uint16 = 334 // withdraw + CommissionTypeAdjust uint16 = 335 // Admin Adjust + GiftTypeIncrease uint16 = 341 // Increase + GiftTypeReduce uint16 = 342 // Reduce +) + +// Uint8 converts Type to uint8. +func (t Type) Uint8() uint8 { + return uint8(t) } -type MessageLog struct { - Id int64 `gorm:"primaryKey"` - Type string `gorm:"type:varchar(50);not null;default:'email';comment:Message Type"` - Platform string `gorm:"type:varchar(50);not null;default:'smtp';comment:Platform"` - To string `gorm:"type:text;not null;comment:To"` - Subject string `gorm:"type:varchar(255);not null;default:'';comment:Subject"` - Content string `gorm:"type:text;comment:Content"` - Status int `gorm:"type:tinyint(1);not null;default:0;comment:Status"` +// SystemLog represents a log entry in the system. +type SystemLog struct { + Id int64 `gorm:"primaryKey;AUTO_INCREMENT"` + Type uint8 `gorm:"index:idx_type;type:tinyint(1);not null;default:0;comment:Log Type: 1: Email Message 2: Mobile Message 3: Subscribe 4: Subscribe Traffic 5: Server Traffic 6: Login 7: Register 8: Balance 9: Commission 10: Reset Subscribe 11: Gift"` + Date string `gorm:"type:varchar(20);default:null;comment:Log Date"` + ObjectID int64 `gorm:"index:idx_object_id;type:bigint(20);not null;default:0;comment:Object ID"` + Content string `gorm:"type:text;not null;comment:Log Content"` CreatedAt time.Time `gorm:"<-:create;comment:Create Time"` - UpdatedAt time.Time `gorm:"comment:Update Time"` } -func (m *MessageLog) TableName() string { - return "message_log" +// TableName returns the name of the table for SystemLogs. +func (SystemLog) TableName() string { + return "system_logs" } -type MessageLogFilterParams struct { - Type string - Platform string - To string - Subject string - Content string - Status int +// Message represents a message log entry. +type Message struct { + To string `json:"to"` + Subject string `json:"subject,omitempty"` + Content map[string]interface{} `json:"content"` + Platform string `json:"platform"` + Template string `json:"template"` + Status uint8 `json:"status"` // 1: Sent, 2: Failed +} + +// Marshal implements the json.Marshaler interface for Message. +func (m *Message) Marshal() ([]byte, error) { + type Alias Message + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(m), + }) +} + +// Unmarshal implements the json.Unmarshaler interface for Message. +func (m *Message) Unmarshal(data []byte) error { + type Alias Message + aux := (*Alias)(m) + return json.Unmarshal(data, aux) +} + +// Traffic represents a subscription traffic log entry. +type Traffic struct { + Download int64 `json:"download"` + Upload int64 `json:"upload"` +} + +// Marshal implements the json.Marshaler interface for SubscribeTraffic. +func (s *Traffic) Marshal() ([]byte, error) { + type Alias Traffic + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(s), + }) +} + +// Unmarshal implements the json.Unmarshaler interface for SubscribeTraffic. +func (s *Traffic) Unmarshal(data []byte) error { + type Alias Traffic + aux := (*Alias)(s) + return json.Unmarshal(data, aux) +} + +// Login represents a login log entry. +type Login struct { + Method string `json:"method"` + LoginIP string `json:"login_ip"` + UserAgent string `json:"user_agent"` + Success bool `json:"success"` + Timestamp int64 `json:"timestamp"` +} + +// Marshal implements the json.Marshaler interface for Login. +func (l *Login) Marshal() ([]byte, error) { + type Alias Login + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(l), + }) +} + +// Unmarshal implements the json.Unmarshaler interface for Login. +func (l *Login) Unmarshal(data []byte) error { + type Alias Login + aux := (*Alias)(l) + return json.Unmarshal(data, aux) +} + +// Register represents a registration log entry. +type Register struct { + AuthMethod string `json:"auth_method"` + Identifier string `json:"identifier"` + RegisterIP string `json:"register_ip"` + UserAgent string `json:"user_agent"` + Timestamp int64 `json:"timestamp"` +} + +// Marshal implements the json.Marshaler interface for Register. +func (r *Register) Marshal() ([]byte, error) { + type Alias Register + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(r), + }) +} + +// Unmarshal implements the json.Unmarshaler interface for Register. + +func (r *Register) Unmarshal(data []byte) error { + type Alias Register + aux := (*Alias)(r) + return json.Unmarshal(data, aux) +} + +// Subscribe represents a subscription log entry. +type Subscribe struct { + Token string `json:"token"` + UserAgent string `json:"user_agent"` + ClientIP string `json:"client_ip"` + UserSubscribeId int64 `json:"user_subscribe_id"` +} + +// Marshal implements the json.Marshaler interface for Subscribe. +func (s *Subscribe) Marshal() ([]byte, error) { + type Alias Subscribe + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(s), + }) +} + +// Unmarshal implements the json.Unmarshaler interface for Subscribe. +func (s *Subscribe) Unmarshal(data []byte) error { + type Alias Subscribe + aux := (*Alias)(s) + return json.Unmarshal(data, aux) +} + +// ResetSubscribe represents a reset subscription log entry. +type ResetSubscribe struct { + Type uint16 `json:"type"` + UserId int64 `json:"user_id"` + OrderNo string `json:"order_no,omitempty"` + Timestamp int64 `json:"timestamp"` +} + +// Marshal implements the json.Marshaler interface for ResetSubscribe. +func (r *ResetSubscribe) Marshal() ([]byte, error) { + type Alias ResetSubscribe + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(r), + }) +} + +// Unmarshal implements the json.Unmarshaler interface for ResetSubscribe. +func (r *ResetSubscribe) Unmarshal(data []byte) error { + type Alias ResetSubscribe + aux := (*Alias)(r) + return json.Unmarshal(data, aux) +} + +// Balance represents a balance log entry. +type Balance struct { + Type uint16 `json:"type"` + Amount int64 `json:"amount"` + OrderNo string `json:"order_no,omitempty"` + Balance int64 `json:"balance"` + Timestamp int64 `json:"timestamp"` +} + +// Marshal implements the json.Marshaler interface for Balance. +func (b *Balance) Marshal() ([]byte, error) { + type Alias Balance + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(b), + }) +} + +// Unmarshal implements the json.Unmarshaler interface for Balance. +func (b *Balance) Unmarshal(data []byte) error { + type Alias Balance + aux := (*Alias)(b) + return json.Unmarshal(data, aux) +} + +// Commission represents a commission log entry. +type Commission struct { + Type uint16 `json:"type"` + Amount int64 `json:"amount"` + OrderNo string `json:"order_no"` + Timestamp int64 `json:"timestamp"` +} + +// Marshal implements the json.Marshaler interface for Commission. +func (c *Commission) Marshal() ([]byte, error) { + type Alias Commission + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(c), + }) +} + +// Unmarshal implements the json.Unmarshaler interface for Commission. +func (c *Commission) Unmarshal(data []byte) error { + type Alias Commission + aux := (*Alias)(c) + return json.Unmarshal(data, aux) +} + +// Gift represents a gift log entry. +type Gift struct { + Type uint16 `json:"type"` + OrderNo string `json:"order_no"` + SubscribeId int64 `json:"subscribe_id"` + Amount int64 `json:"amount"` + Balance int64 `json:"balance"` + Remark string `json:"remark,omitempty"` + Timestamp int64 `json:"timestamp"` +} + +// Marshal implements the json.Marshaler interface for Gift. +func (g *Gift) Marshal() ([]byte, error) { + type Alias Gift + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(g), + }) +} + +// Unmarshal implements the json.Unmarshaler interface for Gift. +func (g *Gift) Unmarshal(data []byte) error { + type Alias Gift + aux := (*Alias)(g) + return json.Unmarshal(data, aux) +} + +// UserTraffic represents a user traffic log entry. +type UserTraffic struct { + SubscribeId int64 `json:"subscribe_id"` // Subscribe ID + UserId int64 `json:"user_id"` // User ID + Upload int64 `json:"upload"` // Upload traffic in bytes + Download int64 `json:"download"` // Download traffic in bytes + Total int64 `json:"total"` // Total traffic in bytes (Upload + Download) +} + +// Marshal implements the json.Marshaler interface for UserTraffic. +func (u *UserTraffic) Marshal() ([]byte, error) { + type Alias UserTraffic + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(u), + }) +} + +// Unmarshal implements the json.Unmarshaler interface for UserTraffic. +func (u *UserTraffic) Unmarshal(data []byte) error { + type Alias UserTraffic + aux := (*Alias)(u) + return json.Unmarshal(data, aux) +} + +// UserTrafficRank represents a user traffic rank entry. +type UserTrafficRank struct { + Rank map[uint8]UserTraffic `json:"rank"` // Key is rank ,type is UserTraffic +} + +// Marshal implements the json.Marshaler interface for UserTrafficRank. +func (u *UserTrafficRank) Marshal() ([]byte, error) { + type Alias UserTrafficRank + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(u), + }) +} + +// Unmarshal implements the json.Unmarshaler interface for UserTrafficRank. +func (u *UserTrafficRank) Unmarshal(data []byte) error { + type Alias UserTrafficRank + aux := (*Alias)(u) + return json.Unmarshal(data, aux) +} + +// ServerTraffic represents a server traffic log entry. +type ServerTraffic struct { + ServerId int64 `json:"server_id"` // Server ID + Upload int64 `json:"upload"` // Upload traffic in bytes + Download int64 `json:"download"` // Download traffic in bytes + Total int64 `json:"total"` // Total traffic in bytes (Upload + Download) +} + +// Marshal implements the json.Marshaler interface for ServerTraffic. +func (s *ServerTraffic) Marshal() ([]byte, error) { + type Alias ServerTraffic + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(s), + }) +} + +// Unmarshal implements the json.Unmarshaler interface for ServerTraffic. +func (s *ServerTraffic) Unmarshal(data []byte) error { + type Alias ServerTraffic + aux := (*Alias)(s) + return json.Unmarshal(data, aux) +} + +// ServerTrafficRank represents a server traffic rank entry. +type ServerTrafficRank struct { + Rank map[uint8]ServerTraffic `json:"rank"` // Key is rank ,type is ServerTraffic +} + +// Marshal implements the json.Marshaler interface for ServerTrafficRank. +func (s *ServerTrafficRank) Marshal() ([]byte, error) { + type Alias ServerTrafficRank + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(s), + }) +} + +// Unmarshal implements the json.Unmarshaler interface for ServerTrafficRank. +func (s *ServerTrafficRank) Unmarshal(data []byte) error { + type Alias ServerTrafficRank + aux := (*Alias)(s) + return json.Unmarshal(data, aux) +} + +// TrafficStat represents a daily traffic statistics log entry. +type TrafficStat struct { + Upload int64 `json:"upload"` + Download int64 `json:"download"` + Total int64 `json:"total"` +} + +// Marshal implements the json.Marshaler interface for TrafficStat. +func (t *TrafficStat) Marshal() ([]byte, error) { + type Alias TrafficStat + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(t), + }) +} + +// Unmarshal implements the json.Unmarshaler interface for TrafficStat. +func (t *TrafficStat) Unmarshal(data []byte) error { + type Alias TrafficStat + aux := (*Alias)(t) + return json.Unmarshal(data, aux) } diff --git a/internal/model/log/model.go b/internal/model/log/model.go index 8bacf15..783b6b8 100644 --- a/internal/model/log/model.go +++ b/internal/model/log/model.go @@ -1,9 +1,63 @@ package log import ( + "context" + "gorm.io/gorm" ) -func NewModel(conn *gorm.DB) Model { - return newLogModel(conn) +func NewModel(db *gorm.DB) Model { + return &customSystemLogModel{ + defaultLogModel: newSystemLogModel(db), + } +} + +type FilterParams struct { + Page int + Size int + Type uint8 + Data string + Search string + ObjectID int64 +} + +type customSystemLogLogicModel interface { + FilterSystemLog(ctx context.Context, filter *FilterParams) ([]*SystemLog, int64, error) +} + +func (m *customSystemLogModel) FilterSystemLog(ctx context.Context, filter *FilterParams) ([]*SystemLog, int64, error) { + tx := m.WithContext(ctx).Model(&SystemLog{}).Order("id DESC") + if filter == nil { + filter = &FilterParams{ + Page: 1, + Size: 10, + } + } + + if filter.Page < 1 { + filter.Page = 1 + } + if filter.Size < 1 { + filter.Size = 10 + } + + if filter.Type != 0 { + tx = tx.Where("`type` = ?", filter.Type) + } + + if filter.Data != "" { + tx = tx.Where("`date` = ?", filter.Data) + } + + if filter.ObjectID != 0 { + tx = tx.Where("`object_id` = ?", filter.ObjectID) + } + if filter.Search != "" { + tx = tx.Where("`content` LIKE ?", "%"+filter.Search+"%") + } + + var total int64 + var logs []*SystemLog + err := tx.Count(&total).Limit(filter.Size).Offset((filter.Page - 1) * filter.Size).Find(&logs).Error + return logs, total, err } diff --git a/internal/model/node/cache.go b/internal/model/node/cache.go new file mode 100644 index 0000000..3e61c9f --- /dev/null +++ b/internal/model/node/cache.go @@ -0,0 +1,146 @@ +package node + +import ( + "context" + "encoding/json" + "fmt" + "time" + + "github.com/pkg/errors" + "github.com/redis/go-redis/v9" +) + +type ( + customCacheLogicModel interface { + StatusCache(ctx context.Context, serverId int64) (Status, error) + UpdateStatusCache(ctx context.Context, serverId int64, status *Status) error + OnlineUserSubscribe(ctx context.Context, serverId int64, protocol string) (OnlineUserSubscribe, error) + UpdateOnlineUserSubscribe(ctx context.Context, serverId int64, protocol string, subscribe OnlineUserSubscribe) error + OnlineUserSubscribeGlobal(ctx context.Context) (int64, error) + UpdateOnlineUserSubscribeGlobal(ctx context.Context, subscribe OnlineUserSubscribe) error + } + + Status struct { + Cpu float64 `json:"cpu"` + Mem float64 `json:"mem"` + Disk float64 `json:"disk"` + UpdatedAt int64 `json:"updated_at"` + } + + OnlineUserSubscribe map[int64][]string +) + +// Marshal to json string +func (s *Status) Marshal() string { + type Alias Status + data, _ := json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(s), + }) + return string(data) +} + +// Unmarshal from json string +func (s *Status) Unmarshal(data string) error { + type Alias Status + aux := &struct { + *Alias + }{ + Alias: (*Alias)(s), + } + return json.Unmarshal([]byte(data), &aux) +} + +const ( + Expiry = 300 * time.Second // Cache expiry time in seconds + StatusCacheKey = "node:status:%d" // Node status cache key format (Server ID and protocol) Example: node:status:1:shadowsocks + OnlineUserCacheKeyWithSubscribe = "node:online:subscribe:%d:%s" // Online user subscribe cache key format (Server ID and protocol) Example: node:online:subscribe:1:shadowsocks + OnlineUserSubscribeCacheKeyWithGlobal = "node:online:subscribe:global" // Online user global subscribe cache key +) + +// UpdateStatusCache Update server status to cache +func (m *customServerModel) UpdateStatusCache(ctx context.Context, serverId int64, status *Status) error { + key := fmt.Sprintf(StatusCacheKey, serverId) + return m.Cache.Set(ctx, key, status.Marshal(), Expiry).Err() + +} + +// StatusCache Get server status from cache +func (m *customServerModel) StatusCache(ctx context.Context, serverId int64) (Status, error) { + var status Status + key := fmt.Sprintf(StatusCacheKey, serverId) + + result, err := m.Cache.Get(ctx, key).Result() + if err != nil { + if errors.Is(err, redis.Nil) { + return status, nil + } + return status, err + } + if result == "" { + return status, nil + } + err = status.Unmarshal(result) + return status, err +} + +// OnlineUserSubscribe Get online user subscribe +func (m *customServerModel) OnlineUserSubscribe(ctx context.Context, serverId int64, protocol string) (OnlineUserSubscribe, error) { + key := fmt.Sprintf(OnlineUserCacheKeyWithSubscribe, serverId, protocol) + result, err := m.Cache.Get(ctx, key).Result() + if err != nil { + if errors.Is(err, redis.Nil) { + return OnlineUserSubscribe{}, nil + } + return nil, err + } + if result == "" { + return OnlineUserSubscribe{}, nil + } + var subscribe OnlineUserSubscribe + err = json.Unmarshal([]byte(result), &subscribe) + return subscribe, err +} + +// UpdateOnlineUserSubscribe Update online user subscribe +func (m *customServerModel) UpdateOnlineUserSubscribe(ctx context.Context, serverId int64, protocol string, subscribe OnlineUserSubscribe) error { + key := fmt.Sprintf(OnlineUserCacheKeyWithSubscribe, serverId, protocol) + data, err := json.Marshal(subscribe) + if err != nil { + return err + } + return m.Cache.Set(ctx, key, data, Expiry).Err() +} + +// OnlineUserSubscribeGlobal Get global online user subscribe count +func (m *customServerModel) OnlineUserSubscribeGlobal(ctx context.Context) (int64, error) { + now := time.Now().Unix() + // Clear expired data + if err := m.Cache.ZRemRangeByScore(ctx, OnlineUserSubscribeCacheKeyWithGlobal, "-inf", fmt.Sprintf("%d", now)).Err(); err != nil { + return 0, err + } + return m.Cache.ZCard(ctx, OnlineUserSubscribeCacheKeyWithGlobal).Result() +} + +// UpdateOnlineUserSubscribeGlobal Update global online user subscribe count +func (m *customServerModel) UpdateOnlineUserSubscribeGlobal(ctx context.Context, subscribe OnlineUserSubscribe) error { + now := time.Now() + expireTime := now.Add(5 * time.Minute).Unix() // set expire time 5 minutes later + + pipe := m.Cache.Pipeline() + + // Clear expired data + pipe.ZRemRangeByScore(ctx, OnlineUserSubscribeCacheKeyWithGlobal, "-inf", fmt.Sprintf("%d", now.Unix())) + // Add or update each subscribe with new expire time + for sub := range subscribe { + // Use ZAdd to add or update the member with new score (expire time) + pipe.ZAdd(ctx, OnlineUserSubscribeCacheKeyWithGlobal, redis.Z{ + Score: float64(expireTime), + Member: sub, + }) + } + + _, err := pipe.Exec(ctx) + return err +} diff --git a/internal/model/node/default.go b/internal/model/node/default.go new file mode 100644 index 0000000..743a3b0 --- /dev/null +++ b/internal/model/node/default.go @@ -0,0 +1,131 @@ +package node + +import ( + "context" + + "github.com/redis/go-redis/v9" + "gorm.io/gorm" +) + +var _ Model = (*customServerModel)(nil) + +//goland:noinspection GoNameStartsWithPackageName +type ( + Model interface { + serverModel + NodeModel + customCacheLogicModel + customServerLogicModel + } + serverModel interface { + InsertServer(ctx context.Context, data *Server, tx ...*gorm.DB) error + FindOneServer(ctx context.Context, id int64) (*Server, error) + UpdateServer(ctx context.Context, data *Server, tx ...*gorm.DB) error + DeleteServer(ctx context.Context, id int64, tx ...*gorm.DB) error + Transaction(ctx context.Context, fn func(db *gorm.DB) error) error + } + + NodeModel interface { + InsertNode(ctx context.Context, data *Node, tx ...*gorm.DB) error + FindOneNode(ctx context.Context, id int64) (*Node, error) + UpdateNode(ctx context.Context, data *Node, tx ...*gorm.DB) error + DeleteNode(ctx context.Context, id int64, tx ...*gorm.DB) error + } + + customServerModel struct { + *defaultServerModel + } + defaultServerModel struct { + *gorm.DB + Cache *redis.Client + } +) + +func newServerModel(db *gorm.DB, cache *redis.Client) *defaultServerModel { + return &defaultServerModel{ + DB: db, + Cache: cache, + } +} + +// NewModel returns a model for the database table. +func NewModel(conn *gorm.DB, cache *redis.Client) Model { + return &customServerModel{ + defaultServerModel: newServerModel(conn, cache), + } +} + +func (m *defaultServerModel) InsertServer(ctx context.Context, data *Server, tx ...*gorm.DB) error { + db := m.DB + if len(tx) > 0 { + db = tx[0] + } + return db.WithContext(ctx).Create(data).Error +} + +func (m *defaultServerModel) FindOneServer(ctx context.Context, id int64) (*Server, error) { + var server Server + err := m.WithContext(ctx).Model(&Server{}).Where("id = ?", id).First(&server).Error + return &server, err +} + +func (m *defaultServerModel) UpdateServer(ctx context.Context, data *Server, tx ...*gorm.DB) error { + _, err := m.FindOneServer(ctx, data.Id) + if err != nil { + return err + } + + db := m.DB + if len(tx) > 0 { + db = tx[0] + } + return db.WithContext(ctx).Save(data).Error + +} + +func (m *defaultServerModel) DeleteServer(ctx context.Context, id int64, tx ...*gorm.DB) error { + db := m.DB + if len(tx) > 0 { + db = tx[0] + } + return db.WithContext(ctx).Where("`id` = ?", id).Delete(&Server{}).Error +} + +func (m *defaultServerModel) InsertNode(ctx context.Context, data *Node, tx ...*gorm.DB) error { + db := m.DB + if len(tx) > 0 { + db = tx[0] + } + return db.WithContext(ctx).Create(data).Error +} + +func (m *defaultServerModel) FindOneNode(ctx context.Context, id int64) (*Node, error) { + var node Node + err := m.WithContext(ctx).Model(&Node{}).Where("id = ?", id).First(&node).Error + return &node, err +} + +func (m *defaultServerModel) UpdateNode(ctx context.Context, data *Node, tx ...*gorm.DB) error { + _, err := m.FindOneNode(ctx, data.Id) + if err != nil { + return err + } + + db := m.DB + if len(tx) > 0 { + db = tx[0] + } + return db.WithContext(ctx).Save(data).Error +} + +func (m *defaultServerModel) DeleteNode(ctx context.Context, id int64, tx ...*gorm.DB) error { + db := m.DB + if len(tx) > 0 { + db = tx[0] + } + return db.WithContext(ctx).Where("`id` = ?", id).Delete(&Node{}).Error +} + +func (m *defaultServerModel) Transaction(ctx context.Context, fn func(db *gorm.DB) error) error { + return m.WithContext(ctx).Transaction(fn) +} diff --git a/internal/model/node/model.go b/internal/model/node/model.go new file mode 100644 index 0000000..119e0e5 --- /dev/null +++ b/internal/model/node/model.go @@ -0,0 +1,157 @@ +package node + +import ( + "context" + "fmt" + + "github.com/perfect-panel/server/pkg/tool" +) + +type customServerLogicModel interface { + FilterServerList(ctx context.Context, params *FilterParams) (int64, []*Server, error) + FilterNodeList(ctx context.Context, params *FilterNodeParams) (int64, []*Node, error) + ClearNodeCache(ctx context.Context, params *FilterNodeParams) error +} + +const ( + // ServerUserListCacheKey Server User List Cache Key + ServerUserListCacheKey = "server:user:" + + // ServerConfigCacheKey Server Config Cache Key + ServerConfigCacheKey = "server:config:" +) + +// FilterParams Filter Server Params +type FilterParams struct { + Page int + Size int + Ids []int64 // Server IDs + Search string +} + +type FilterNodeParams struct { + Page int // Page Number + Size int // Page Size + ServerId []int64 // Server IDs + Tag []string // Tags + Search string // Search Address or Name + Protocol string // Protocol + Preload bool // Preload Server +} + +// FilterServerList Filter Server List +func (m *customServerModel) FilterServerList(ctx context.Context, params *FilterParams) (int64, []*Server, error) { + var servers []*Server + var total int64 + query := m.WithContext(ctx).Model(&Server{}) + if params == nil { + params = &FilterParams{ + Page: 1, + Size: 10, + } + } + if params.Search != "" { + s := "%" + params.Search + "%" + query = query.Where("`name` LIKE ? OR `address` LIKE ?", s, s) + } + if len(params.Ids) > 0 { + query = query.Where("id IN ?", params.Ids) + } + err := query.Count(&total).Limit(params.Size).Offset((params.Page - 1) * params.Size).Find(&servers).Error + return total, servers, err +} + +// FilterNodeList Filter Node List +func (m *customServerModel) FilterNodeList(ctx context.Context, params *FilterNodeParams) (int64, []*Node, error) { + var nodes []*Node + var total int64 + query := m.WithContext(ctx).Model(&Node{}) + if params == nil { + params = &FilterNodeParams{ + Page: 1, + Size: 10, + } + } + if params.Search != "" { + s := "%" + params.Search + "%" + query = query.Where("`name` LIKE ? OR `address` LIKE ? OR `tags` LIKE ? OR `port` LIKE ? ", s, s, s, s) + } + if len(params.ServerId) > 0 { + query = query.Where("server_id IN ?", params.ServerId) + } + if len(params.Tag) > 0 { + for _, tag := range params.Tag { + query = query.Or("FIND_IN_SET(?,tags)", tag) + } + } + if params.Protocol != "" { + query = query.Where("protocol = ?", params.Protocol) + } + + if params.Preload { + query = query.Preload("Server") + } + + err := query.Count(&total).Limit(params.Size).Offset((params.Page - 1) * params.Size).Find(&nodes).Error + return total, nodes, err +} + +// ClearNodeCache Clear Node Cache +func (m *customServerModel) ClearNodeCache(ctx context.Context, params *FilterNodeParams) error { + _, nodes, err := m.FilterNodeList(ctx, params) + if err != nil { + return err + } + var cacheKeys []string + for _, node := range nodes { + cacheKeys = append(cacheKeys, fmt.Sprintf("%s%d", ServerUserListCacheKey, node.ServerId)) + if node.Protocol != "" { + var cursor uint64 + for { + keys, newCursor, err := m.Cache.Scan(ctx, cursor, fmt.Sprintf("%s%d*", ServerConfigCacheKey, node.ServerId), 100).Result() + if err != nil { + return err + } + if len(keys) > 0 { + cacheKeys = append(keys, keys...) + } + cursor = newCursor + if cursor == 0 { + break + } + } + } + } + + if len(cacheKeys) > 0 { + cacheKeys = tool.RemoveDuplicateElements(cacheKeys...) + return m.Cache.Del(ctx, cacheKeys...).Err() + } + return nil +} + +// ClearServerCache Clear Server Cache +func (m *customServerModel) ClearServerCache(ctx context.Context, serverId int64) error { + var cacheKeys []string + cacheKeys = append(cacheKeys, fmt.Sprintf("%s%d", ServerUserListCacheKey, serverId)) + var cursor uint64 + for { + keys, newCursor, err := m.Cache.Scan(ctx, 0, fmt.Sprintf("%s%d*", ServerConfigCacheKey, serverId), 100).Result() + if err != nil { + return err + } + if len(keys) > 0 { + cacheKeys = append(cacheKeys, keys...) + } + cursor = newCursor + if cursor == 0 { + break + } + } + + if len(cacheKeys) > 0 { + cacheKeys = tool.RemoveDuplicateElements(cacheKeys...) + return m.Cache.Del(ctx, cacheKeys...).Err() + } + return nil +} diff --git a/internal/model/node/node.go b/internal/model/node/node.go new file mode 100644 index 0000000..89d665d --- /dev/null +++ b/internal/model/node/node.go @@ -0,0 +1,82 @@ +package node + +import ( + "time" + + "github.com/perfect-panel/server/pkg/logger" + "gorm.io/gorm" +) + +type Node struct { + Id int64 `gorm:"primary_key"` + Name string `gorm:"type:varchar(100);not null;default:'';comment:Node Name"` + Tags string `gorm:"type:varchar(255);not null;default:'';comment:Tags"` + Port uint16 `gorm:"not null;default:0;comment:Connect Port"` + Address string `gorm:"type:varchar(255);not null;default:'';comment:Connect Address"` + ServerId int64 `gorm:"not null;default:0;comment:Server ID"` + Server *Server `gorm:"foreignKey:ServerId;references:Id"` + Protocol string `gorm:"type:varchar(100);not null;default:'';comment:Protocol"` + Enabled *bool `gorm:"type:boolean;not null;default:true;comment:Enabled"` + Sort int `gorm:"uniqueIndex;not null;default:0;comment:Sort"` + CreatedAt time.Time `gorm:"<-:create;comment:Creation Time"` + UpdatedAt time.Time `gorm:"comment:Update Time"` +} + +func (n *Node) TableName() string { + return "nodes" +} + +func (n *Node) BeforeCreate(tx *gorm.DB) error { + if n.Sort == 0 { + var maxSort int + if err := tx.Model(&Node{}).Select("COALESCE(MAX(sort), 0)").Scan(&maxSort).Error; err != nil { + return err + } + n.Sort = maxSort + 1 + } + return nil +} + +func (n *Node) BeforeDelete(tx *gorm.DB) error { + if err := tx.Exec("UPDATE `nodes` SET sort = sort - 1 WHERE sort > ?", n.Sort).Error; err != nil { + return err + } + return nil +} + +func (n *Node) BeforeUpdate(tx *gorm.DB) error { + var count int64 + if err := tx.Set("gorm:query_option", "FOR UPDATE").Model(&Server{}). + Where("sort = ? AND id != ?", n.Sort, n.Id).Count(&count).Error; err != nil { + return err + } + if count > 1 { + // reorder sort + if err := reorderSortWithNode(tx); err != nil { + logger.Errorf("[Server] BeforeUpdate reorderSort error: %v", err.Error()) + return err + } + // get max sort + var maxSort int + if err := tx.Model(&Server{}).Select("MAX(sort)").Scan(&maxSort).Error; err != nil { + return err + } + n.Sort = maxSort + 1 + } + return nil +} + +func reorderSortWithNode(tx *gorm.DB) error { + var nodes []Node + if err := tx.Order("sort, id").Find(&nodes).Error; err != nil { + return err + } + for i, node := range nodes { + if node.Sort != i+1 { + if err := tx.Exec("UPDATE `nodes` SET sort = ? WHERE id = ?", i+1, node.Id).Error; err != nil { + return err + } + } + } + return nil +} diff --git a/internal/model/node/server.go b/internal/model/node/server.go new file mode 100644 index 0000000..9f6d401 --- /dev/null +++ b/internal/model/node/server.go @@ -0,0 +1,171 @@ +package node + +import ( + "encoding/json" + "time" + + "github.com/perfect-panel/server/pkg/logger" + "github.com/pkg/errors" + "gorm.io/gorm" +) + +type Server struct { + Id int64 `gorm:"primary_key"` + Name string `gorm:"type:varchar(100);not null;default:'';comment:Server Name"` + Country string `gorm:"type:varchar(128);not null;default:'';comment:Country"` + City string `gorm:"type:varchar(128);not null;default:'';comment:City"` + Ratio float32 `gorm:"type:DECIMAL(4,2);not null;default:0;comment:Traffic Ratio"` + Address string `gorm:"type:varchar(100);not null;default:'';comment:Server Address"` + Sort int `gorm:"type:int;not null;default:0;comment:Sort"` + Protocols string `gorm:"type:text;default:null;comment:Protocol"` + LastReportedAt *time.Time `gorm:"comment:Last Reported Time"` + CreatedAt time.Time `gorm:"<-:create;comment:Creation Time"` + UpdatedAt time.Time `gorm:"comment:Update Time"` +} + +func (*Server) TableName() string { + return "servers" +} + +func (m *Server) BeforeCreate(tx *gorm.DB) error { + if m.Sort == 0 { + var maxSort int + if err := tx.Model(&Server{}).Select("COALESCE(MAX(sort), 0)").Scan(&maxSort).Error; err != nil { + return err + } + m.Sort = maxSort + 1 + } + return nil +} + +func (m *Server) BeforeDelete(tx *gorm.DB) error { + if err := tx.Exec("UPDATE `servers` SET sort = sort - 1 WHERE sort > ?", m.Sort).Error; err != nil { + return err + } + return nil +} + +func (m *Server) BeforeUpdate(tx *gorm.DB) error { + var count int64 + if err := tx.Set("gorm:query_option", "FOR UPDATE").Model(&Server{}). + Where("sort = ? AND id != ?", m.Sort, m.Id).Count(&count).Error; err != nil { + return err + } + if count > 1 { + // reorder sort + if err := reorderSortWithServer(tx); err != nil { + logger.Errorf("[Server] BeforeUpdate reorderSort error: %v", err.Error()) + return err + } + // get max sort + var maxSort int + if err := tx.Model(&Server{}).Select("MAX(sort)").Scan(&maxSort).Error; err != nil { + return err + } + m.Sort = maxSort + 1 + } + return nil +} + +// MarshalProtocols Marshal server protocols to json +func (m *Server) MarshalProtocols(list []Protocol) error { + var validate = make(map[string]bool) + for _, protocol := range list { + if protocol.Type == "" { + return errors.New("protocol type is required") + } + if _, exists := validate[protocol.Type]; exists { + return errors.New("duplicate protocol type: " + protocol.Type) + } + validate[protocol.Type] = true + } + data, err := json.Marshal(list) + if err != nil { + return err + } + m.Protocols = string(data) + return nil +} + +// UnmarshalProtocols Unmarshal server protocols from json +func (m *Server) UnmarshalProtocols() ([]Protocol, error) { + var list []Protocol + if m.Protocols == "" { + return list, nil + } + err := json.Unmarshal([]byte(m.Protocols), &list) + if err != nil { + return nil, err + } + return list, nil +} + +type Protocol struct { + Type string `json:"type"` + Port uint16 `json:"port"` + Security string `json:"security,omitempty"` + SNI string `json:"sni,omitempty"` + AllowInsecure bool `json:"allow_insecure,omitempty"` + Fingerprint string `json:"fingerprint,omitempty"` + RealityServerAddr string `json:"reality_server_addr,omitempty"` + RealityServerPort int `json:"reality_server_port,omitempty"` + RealityPrivateKey string `json:"reality_private_key,omitempty"` + RealityPublicKey string `json:"reality_public_key,omitempty"` + RealityShortId string `json:"reality_short_id,omitempty"` + Transport string `json:"transport,omitempty"` + Host string `json:"host,omitempty"` + Path string `json:"path,omitempty"` + ServiceName string `json:"service_name,omitempty"` + Cipher string `json:"cipher,omitempty"` + ServerKey string `json:"server_key,omitempty"` + Flow string `json:"flow,omitempty"` + HopPorts string `json:"hop_ports,omitempty"` + HopInterval int `json:"hop_interval,omitempty"` + ObfsPassword string `json:"obfs_password,omitempty"` + DisableSNI bool `json:"disable_sni,omitempty"` + ReduceRtt bool `json:"reduce_rtt,omitempty"` + UDPRelayMode string `json:"udp_relay_mode,omitempty"` + CongestionController string `json:"congestion_controller,omitempty"` + Plugin string `json:"plugin,omitempty"` // obfs, v2ray-plugin, simple-obfs + PluginOptions string `json:"plugin_options,omitempty"` // plugin options, eg: obfs=http;obfs-host=www.bing.com + Multiplex string `json:"multiplex,omitempty"` // mux, eg: off/low/medium/high + PaddingScheme string `json:"padding_scheme,omitempty"` // padding scheme + UpMbps int `json:"up_mbps,omitempty"` // upload speed limit + DownMbps int `json:"down_mbps,omitempty"` // download speed limit +} + +// Marshal protocol to json +func (m *Protocol) Marshal() ([]byte, error) { + type Alias Protocol + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(m), + }) +} + +// Unmarshal json to protocol +func (m *Protocol) Unmarshal(data []byte) error { + type Alias Protocol + aux := &struct { + *Alias + }{ + Alias: (*Alias)(m), + } + return json.Unmarshal(data, &aux) +} + +func reorderSortWithServer(tx *gorm.DB) error { + var servers []Server + if err := tx.Order("sort, id").Find(&servers).Error; err != nil { + return err + } + for i, server := range servers { + if server.Sort != i+1 { + if err := tx.Exec("UPDATE `servers` SET sort = ? WHERE id = ?", i+1, server.Id).Error; err != nil { + return err + } + } + } + return nil +} diff --git a/internal/model/order/model.go b/internal/model/order/model.go index b8f2377..d98e361 100644 --- a/internal/model/order/model.go +++ b/internal/model/order/model.go @@ -63,6 +63,12 @@ type customOrderLogicModel interface { QueryMonthlyOrdersList(ctx context.Context, date time.Time) ([]OrdersTotalWithDate, error) } +// UserCounts User counts for new and renewal users +type UserCounts struct { + NewUsers int64 `gorm:"column:new_users"` + RenewalUsers int64 `gorm:"column:renewal_users"` +} + // NewModel returns a model for the database table. func NewModel(conn *gorm.DB, c *redis.Client) Model { return &customOrderModel{ @@ -165,65 +171,78 @@ func (m *customOrderModel) QueryDateOrders(ctx context.Context, date time.Time) func (m *customOrderModel) QueryTotalOrders(ctx context.Context) (OrdersTotal, error) { var result OrdersTotal - err := m.QueryNoCacheCtx(ctx, &result, func(conn *gorm.DB, v interface{}) error { + + err := m.QueryNoCacheCtx(ctx, &result, func(conn *gorm.DB, _ interface{}) error { return conn.Model(&Order{}). + Select(` + SUM(amount) AS amount_total, + SUM(CASE WHEN is_new = 1 THEN amount ELSE 0 END) AS new_order_amount, + SUM(CASE WHEN is_new = 0 THEN amount ELSE 0 END) AS renewal_order_amount + `). Where("status IN ? AND method != ?", []int64{2, 5}, "balance"). - Select( - "SUM(amount) as amount_total, " + - "SUM(CASE WHEN is_new = 1 THEN amount ELSE 0 END) as new_order_amount, " + - "SUM(CASE WHEN is_new = 0 THEN amount ELSE 0 END) as renewal_order_amount", - ). - Scan(v).Error + Scan(&result).Error }) + return result, err } func (m *customOrderModel) QueryMonthlyUserCounts(ctx context.Context, date time.Time) (int64, int64, error) { + // 获取当月第一天零点 firstDay := time.Date(date.Year(), date.Month(), 1, 0, 0, 0, 0, date.Location()) - lastDay := firstDay.AddDate(0, 1, -1) + // 获取下个月第一天零点(避免漏掉最后一天的订单) + nextMonth := firstDay.AddDate(0, 1, 0) - var newUsers int64 - var renewalUsers int64 + var counts UserCounts + + // 执行查询 err := m.QueryNoCacheCtx(ctx, nil, func(conn *gorm.DB, _ interface{}) error { return conn.Model(&Order{}). - Where("status IN ? AND created_at BETWEEN ? AND ? AND method != ?", []int64{2, 5}, firstDay, lastDay, "balance"). - Select( - "COUNT(DISTINCT CASE WHEN is_new = 1 THEN user_id END) as new_users, "+ - "COUNT(DISTINCT CASE WHEN is_new = 0 THEN user_id END) as renewal_users"). - Row().Scan(&newUsers, &renewalUsers) + Select(` + COUNT(DISTINCT CASE WHEN is_new = 1 THEN user_id END) AS new_users, + COUNT(DISTINCT CASE WHEN is_new = 0 THEN user_id END) AS renewal_users + `). + Where("status IN ? AND created_at >= ? AND created_at < ? AND method != ?", + []int64{2, 5}, firstDay, nextMonth, "balance"). + Scan(&counts).Error }) - return newUsers, renewalUsers, err -} + return counts.NewUsers, counts.RenewalUsers, err +} func (m *customOrderModel) QueryDateUserCounts(ctx context.Context, date time.Time) (int64, int64, error) { - start := date.Truncate(24 * time.Hour) - end := start.Add(24 * time.Hour).Add(-time.Nanosecond) + // 当天 00:00:00 + start := time.Date(date.Year(), date.Month(), date.Day(), 0, 0, 0, 0, date.Location()) + // 下一天 00:00:00 + nextDay := start.Add(24 * time.Hour) + + var counts UserCounts - var newUsers int64 - var renewalUsers int64 err := m.QueryNoCacheCtx(ctx, nil, func(conn *gorm.DB, _ interface{}) error { return conn.Model(&Order{}). - Where("status IN ? AND created_at BETWEEN ? AND ? AND method != ?", []int64{2, 5}, start, end, "balance"). - Select( - "COUNT(DISTINCT CASE WHEN is_new = 1 THEN user_id END) as new_users, "+ - "COUNT(DISTINCT CASE WHEN is_new = 0 THEN user_id END) as renewal_users"). - Row().Scan(&newUsers, &renewalUsers) + Select(` + COUNT(DISTINCT CASE WHEN is_new = 1 THEN user_id END) AS new_users, + COUNT(DISTINCT CASE WHEN is_new = 0 THEN user_id END) AS renewal_users + `). + Where("status IN ? AND created_at >= ? AND created_at < ? AND method != ?", + []int64{2, 5}, start, nextDay, "balance"). + Scan(&counts).Error }) - return newUsers, renewalUsers, err -} + return counts.NewUsers, counts.RenewalUsers, err +} func (m *customOrderModel) QueryTotalUserCounts(ctx context.Context) (int64, int64, error) { - var newUsers int64 - var renewalUsers int64 + var counts UserCounts + err := m.QueryNoCacheCtx(ctx, nil, func(conn *gorm.DB, _ interface{}) error { return conn.Model(&Order{}). Where("status IN ? AND method != ?", []int64{2, 5}, "balance"). - Select( - "COUNT(DISTINCT CASE WHEN is_new = 1 THEN user_id END) as new_users, "+ - "COUNT(DISTINCT CASE WHEN is_new = 0 THEN user_id END) as renewal_users"). - Row().Scan(&newUsers, &renewalUsers) + Select(` + COUNT(DISTINCT CASE WHEN is_new = 1 THEN user_id END) AS new_users, + COUNT(DISTINCT CASE WHEN is_new = 0 THEN user_id END) AS renewal_users + `). + Scan(&counts).Error }) - return newUsers, renewalUsers, err + + return counts.NewUsers, counts.RenewalUsers, err } func (m *customOrderModel) IsUserEligibleForNewOrder(ctx context.Context, userID int64) (bool, error) { @@ -236,39 +255,51 @@ func (m *customOrderModel) IsUserEligibleForNewOrder(ctx context.Context, userID return count == 0, err } -// QueryDailyOrdersList Query daily orders list for the current month (from 1st to current date) +// QueryDailyOrdersList 查询当月每日订单统计 func (m *customOrderModel) QueryDailyOrdersList(ctx context.Context, date time.Time) ([]OrdersTotalWithDate, error) { var results []OrdersTotalWithDate + err := m.QueryNoCacheCtx(ctx, &results, func(conn *gorm.DB, v interface{}) error { + // 当月 1 号 00:00:00 firstDay := time.Date(date.Year(), date.Month(), 1, 0, 0, 0, 0, date.Location()) + // 第二天 00:00:00 + nextDay := date.AddDate(0, 0, 1).Truncate(24 * time.Hour) + return conn.Model(&Order{}). - Where("status IN ? AND created_at BETWEEN ? AND ? AND method != ?", []int64{2, 5}, firstDay, date, "balance"). - Select( - "DATE(created_at) as date, " + - "SUM(amount) as amount_total, " + - "SUM(CASE WHEN is_new = 1 THEN amount ELSE 0 END) as new_order_amount, " + - "SUM(CASE WHEN is_new = 0 THEN amount ELSE 0 END) as renewal_order_amount", - ). - Group("DATE(created_at)"). + Select(` + DATE_FORMAT(created_at, '%Y-%m-%d') AS date, + SUM(amount) AS amount_total, + SUM(CASE WHEN is_new = 1 THEN amount ELSE 0 END) AS new_order_amount, + SUM(CASE WHEN is_new = 0 THEN amount ELSE 0 END) AS renewal_order_amount + `). + Where("status IN ? AND created_at >= ? AND created_at < ? AND method != ?", + []int64{2, 5}, firstDay, nextDay, "balance"). + Group("DATE_FORMAT(created_at, '%Y-%m-%d')"). Order("date ASC"). Scan(v).Error }) return results, err } -// QueryMonthlyOrdersList Query monthly orders list for the past 6 months +// QueryMonthlyOrdersList 查询过去 6 个月订单统计(包含当前月) func (m *customOrderModel) QueryMonthlyOrdersList(ctx context.Context, date time.Time) ([]OrdersTotalWithDate, error) { var results []OrdersTotalWithDate + err := m.QueryNoCacheCtx(ctx, &results, func(conn *gorm.DB, v interface{}) error { - sixMonthsAgo := date.AddDate(0, -5, 0) + // 六个月前(取月初) + start := time.Date(date.Year(), date.Month(), 1, 0, 0, 0, 0, date.Location()).AddDate(0, -5, 0) + // 下个月月初 + end := time.Date(date.Year(), date.Month(), 1, 0, 0, 0, 0, date.Location()).AddDate(0, 1, 0) + return conn.Model(&Order{}). - Where("status IN ? AND created_at >= ? AND method != ?", []int64{2, 5}, sixMonthsAgo, "balance"). - Select( - "DATE_FORMAT(created_at, '%Y-%m') as date, " + - "SUM(amount) as amount_total, " + - "SUM(CASE WHEN is_new = 1 THEN amount ELSE 0 END) as new_order_amount, " + - "SUM(CASE WHEN is_new = 0 THEN amount ELSE 0 END) as renewal_order_amount", - ). + Select(` + DATE_FORMAT(created_at, '%Y-%m') AS date, + SUM(amount) AS amount_total, + SUM(CASE WHEN is_new = 1 THEN amount ELSE 0 END) AS new_order_amount, + SUM(CASE WHEN is_new = 0 THEN amount ELSE 0 END) AS renewal_order_amount + `). + Where("status IN ? AND created_at >= ? AND created_at < ? AND method != ?", + []int64{2, 5}, start, end, "balance"). Group("DATE_FORMAT(created_at, '%Y-%m')"). Order("date ASC"). Scan(v).Error diff --git a/internal/model/payment/payment.go b/internal/model/payment/payment.go index b76a61f..46ee0a0 100644 --- a/internal/model/payment/payment.go +++ b/internal/model/payment/payment.go @@ -46,13 +46,19 @@ type StripeConfig struct { Payment string `json:"payment"` } -func (l *StripeConfig) Marshal() string { - b, _ := json.Marshal(l) - return string(b) +func (l *StripeConfig) Marshal() ([]byte, error) { + type Alias StripeConfig + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(l), + }) } -func (l *StripeConfig) Unmarshal(s string) error { - return json.Unmarshal([]byte(s), l) +func (l *StripeConfig) Unmarshal(data []byte) error { + type Alias StripeConfig + aux := (*Alias)(l) + return json.Unmarshal(data, &aux) } type AlipayF2FConfig struct { @@ -63,13 +69,19 @@ type AlipayF2FConfig struct { Sandbox bool `json:"sandbox"` } -func (l *AlipayF2FConfig) Marshal() string { - b, _ := json.Marshal(l) - return string(b) +func (l *AlipayF2FConfig) Marshal() ([]byte, error) { + type Alias AlipayF2FConfig + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(l), + }) } -func (l *AlipayF2FConfig) Unmarshal(s string) error { - return json.Unmarshal([]byte(s), l) +func (l *AlipayF2FConfig) Unmarshal(data []byte) error { + type Alias AlipayF2FConfig + aux := (*Alias)(l) + return json.Unmarshal(data, &aux) } type EPayConfig struct { @@ -78,11 +90,38 @@ type EPayConfig struct { Key string `json:"key"` } -func (l *EPayConfig) Marshal() string { - b, _ := json.Marshal(l) - return string(b) +func (l *EPayConfig) Marshal() ([]byte, error) { + type Alias EPayConfig + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(l), + }) } -func (l *EPayConfig) Unmarshal(s string) error { - return json.Unmarshal([]byte(s), l) +func (l *EPayConfig) Unmarshal(data []byte) error { + type Alias EPayConfig + aux := (*Alias)(l) + return json.Unmarshal(data, &aux) +} + +type CryptoSaaSConfig struct { + Endpoint string `json:"endpoint"` + AccountID string `json:"account_id"` + SecretKey string `json:"secret_key"` +} + +func (l *CryptoSaaSConfig) Marshal() ([]byte, error) { + type Alias CryptoSaaSConfig + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(l), + }) +} + +func (l *CryptoSaaSConfig) Unmarshal(data []byte) error { + type Alias CryptoSaaSConfig + aux := (*Alias)(l) + return json.Unmarshal(data, &aux) } diff --git a/internal/model/server/default.go b/internal/model/server/default.go index 408a72f..b013f1a 100644 --- a/internal/model/server/default.go +++ b/internal/model/server/default.go @@ -5,8 +5,6 @@ import ( "errors" "fmt" - "github.com/perfect-panel/server/internal/config" - "github.com/perfect-panel/server/pkg/cache" "github.com/redis/go-redis/v9" "gorm.io/gorm" @@ -62,20 +60,23 @@ func (m *defaultServerModel) batchGetCacheKeys(Servers ...*Server) []string { return keys } + func (m *defaultServerModel) getCacheKeys(data *Server) []string { if data == nil { return []string{} } detailsKey := fmt.Sprintf("%s%v", CacheServerDetailPrefix, data.Id) ServerIdKey := fmt.Sprintf("%s%v", cacheServerIdPrefix, data.Id) - configIdKey := fmt.Sprintf("%s%v", config.ServerConfigCacheKey, data.Id) - userIDKey := fmt.Sprintf("%s%d", config.ServerUserListCacheKey, data.Id) + //configIdKey := fmt.Sprintf("%s%v", config.ServerConfigCacheKey, data.Id) + //userIDKey := fmt.Sprintf("%s%d", config.ServerUserListCacheKey, data.Id) + + // query protocols to get config keys cacheKeys := []string{ ServerIdKey, detailsKey, - configIdKey, - userIDKey, + //configIdKey, + //userIDKey, } return cacheKeys } diff --git a/internal/model/server/model.go b/internal/model/server/model.go index 0c423ff..58ae7b7 100644 --- a/internal/model/server/model.go +++ b/internal/model/server/model.go @@ -5,7 +5,6 @@ import ( "fmt" "strings" - "github.com/perfect-panel/server/internal/config" "gorm.io/gorm" ) @@ -45,10 +44,10 @@ var ( // ClearCache Clear Cache func (m *customServerModel) ClearCache(ctx context.Context, id int64) error { serverIdKey := fmt.Sprintf("%s%v", cacheServerIdPrefix, id) - configKey := fmt.Sprintf("%s%d", config.ServerConfigCacheKey, id) - userListKey := fmt.Sprintf("%s%v", config.ServerUserListCacheKey, id) + //configKey := fmt.Sprintf("%s%d", config.ServerConfigCacheKey, id) + //userListKey := fmt.Sprintf("%s%v", config.ServerUserListCacheKey, id) - return m.DelCacheCtx(ctx, serverIdKey, configKey, userListKey) + return m.DelCacheCtx(ctx, serverIdKey) } // QueryServerCountByServerGroups Query Server Count By Server Groups diff --git a/internal/model/server/server.go b/internal/model/server/server.go index 572840f..2da10da 100644 --- a/internal/model/server/server.go +++ b/internal/model/server/server.go @@ -26,6 +26,7 @@ type ServerFilter struct { Size int } +// Deprecated: use internal/model/node/server.go type Server struct { Id int64 `gorm:"primary_key"` Name string `gorm:"type:varchar(100);not null;default:'';comment:Node Name"` diff --git a/internal/model/subscribe/default.go b/internal/model/subscribe/default.go index 92879d7..29e748c 100644 --- a/internal/model/subscribe/default.go +++ b/internal/model/subscribe/default.go @@ -4,12 +4,11 @@ import ( "context" "errors" "fmt" - "strconv" "strings" - "github.com/perfect-panel/server/internal/config" - "github.com/perfect-panel/server/internal/model/server" + "github.com/perfect-panel/server/internal/model/node" "github.com/perfect-panel/server/pkg/cache" + "github.com/perfect-panel/server/pkg/tool" "github.com/redis/go-redis/v9" "gorm.io/gorm" ) @@ -61,42 +60,34 @@ func (m *defaultSubscribeModel) getCacheKeys(data *Subscribe) []string { if data == nil { return []string{} } - SubscribeIdKey := fmt.Sprintf("%s%v", cacheSubscribeIdPrefix, data.Id) - serverKey := make([]string, 0) - if data.Server != "" { - cacheKey := strings.Split(data.Server, ",") - for _, v := range cacheKey { - if v != "" { - serverKey = append(serverKey, fmt.Sprintf("%s%v", config.ServerUserListCacheKey, v)) + var keys []string + if data.Nodes != "" { + var nodes []*node.Node + ids := strings.Split(data.Nodes, ",") + + err := m.QueryNoCacheCtx(context.Background(), &nodes, func(conn *gorm.DB, v interface{}) error { + return conn.Model(&node.Node{}).Where("id IN (?)", tool.StringSliceToInt64Slice(ids)).Find(&nodes).Error + }) + if err == nil { + for _, n := range nodes { + keys = append(keys, fmt.Sprintf("%s%d", node.ServerUserListCacheKey, n.ServerId)) } } } - // Temporary solution waiting for refactoring - if data.ServerGroup != "" { - cacheKey := strings.Split(data.ServerGroup, ",") - groupIds := make([]int64, 0) - for _, v := range cacheKey { - if v != "" { - id, _ := strconv.ParseInt(v, 10, 64) - if id > 0 { - groupIds = append(groupIds, id) - } - } - } - var ids []int64 - _ = m.Transaction(context.Background(), func(tx *gorm.DB) error { - return tx.Model(&server.Server{}).Where("group_id IN ?", groupIds).Pluck("id", &ids).Error + if data.NodeTags != "" { + var nodes []*node.Node + tags := tool.RemoveDuplicateElements(strings.Split(data.NodeTags, ",")...) + err := m.QueryNoCacheCtx(context.Background(), &nodes, func(conn *gorm.DB, v interface{}) error { + return conn.Model(&node.Node{}).Scopes(InSet("tags", tags)).Find(&nodes).Error }) - for _, id := range ids { - serverKey = append(serverKey, fmt.Sprintf("%s%v", config.ServerUserListCacheKey, id)) + if err == nil { + for _, n := range nodes { + keys = append(keys, fmt.Sprintf("%s%d", node.ServerUserListCacheKey, n.ServerId)) + } } } - cacheKeys := []string{SubscribeIdKey} - if len(serverKey) > 0 { - cacheKeys = append(cacheKeys, serverKey...) - } - return cacheKeys + return append(keys, fmt.Sprintf("%s%v", cacheSubscribeIdPrefix, data.Id)) } func (m *defaultSubscribeModel) Insert(ctx context.Context, data *Subscribe, tx ...*gorm.DB) error { diff --git a/internal/model/subscribe/model.go b/internal/model/subscribe/model.go index f652bc1..9942046 100644 --- a/internal/model/subscribe/model.go +++ b/internal/model/subscribe/model.go @@ -3,39 +3,37 @@ package subscribe import ( "context" + "github.com/perfect-panel/server/pkg/tool" "github.com/redis/go-redis/v9" "gorm.io/gorm" ) -// type Details struct { -// Id int64 `gorm:"primaryKey"` -// Name string `gorm:"type:varchar(255);not null;default:'';comment:Subscribe Name"` -// Description string `gorm:"type:text;comment:Subscribe Description"` -// UnitPrice int64 `gorm:"type:int;not null;default:0;comment:Unit Price"` -// UnitTime string `gorm:"type:varchar(255);not null;default:'';comment:Unit Time"` -// Discount string `gorm:"type:text;comment:Discount"` -// Replacement int64 `gorm:"type:int;not null;default:0;comment:Replacement"` -// Inventory int64 `gorm:"type:int;not null;default:0;comment:Inventory"` -// Traffic int64 `gorm:"type:int;not null;default:0;comment:Traffic"` -// SpeedLimit int64 `gorm:"type:int;not null;default:0;comment:Speed Limit"` -// DeviceLimit int64 `gorm:"type:int;not null;default:0;comment:Device Limit"` -// GroupId int64 `gorm:"type:bigint;comment:Group Id"` -// Quota int64 `gorm:"type:int;not null;default:0;comment:Quota"` -// Show *bool `gorm:"type:tinyint(1);not null;default:0;comment:Show"` -// Sell *bool `gorm:"type:tinyint(1);not null;default:0;comment:Sell"` -// DeductionRatio int64 `gorm:"type:int;default:0;comment:Deduction Ratio"` -// PurchaseWithDiscount bool `gorm:"type:tinyint(1);default:0;comment:PurchaseWithDiscount"` -// ResetCycle int64 `gorm:"type:int;default:0;comment:Reset Cycle"` -// RenewalReset bool `gorm:"type:tinyint(1);default:0;comment:Renew Reset"` -// } +type FilterParams struct { + Page int // Page Number + Size int // Page Size + Ids []int64 // Subscribe IDs + Node []int64 // Node IDs + Tags []string // Node Tags + Show bool // Show Portal Page + Sell bool // Sell + Language string // Language + DefaultLanguage bool // Default Subscribe Language Data + Search string // Search Keywords +} + +func (p *FilterParams) Normalize() { + if p.Page <= 0 { + p.Page = 1 + } + if p.Size <= 0 { + p.Size = 10 + } +} + type customSubscribeLogicModel interface { - QuerySubscribeListByPage(ctx context.Context, page, size int, group int64, search string) (total int64, list []*Subscribe, err error) - QuerySubscribeList(ctx context.Context) ([]*Subscribe, error) - QuerySubscribeListByShow(ctx context.Context) ([]*Subscribe, error) - QuerySubscribeIdsByServerIdAndServerGroupId(ctx context.Context, serverId, serverGroupId int64) ([]*Subscribe, error) - QuerySubscribeMinSortByIds(ctx context.Context, ids []int64) (int64, error) - QuerySubscribeListByIds(ctx context.Context, ids []int64) ([]*Subscribe, error) + FilterList(ctx context.Context, params *FilterParams) (int64, []*Subscribe, error) ClearCache(ctx context.Context, id ...int64) error + QuerySubscribeMinSortByIds(ctx context.Context, ids []int64) (int64, error) } // NewModel returns a model for the database table. @@ -45,54 +43,6 @@ func NewModel(conn *gorm.DB, c *redis.Client) Model { } } -// QuerySubscribeListByPage Get Subscribe List -func (m *customSubscribeModel) QuerySubscribeListByPage(ctx context.Context, page, size int, group int64, search string) (total int64, list []*Subscribe, err error) { - err = m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error { - // About to be abandoned - _ = conn.Model(&Subscribe{}). - Where("sort = ?", 0). - Update("sort", gorm.Expr("id")) - - conn = conn.Model(&Subscribe{}) - if group > 0 { - conn = conn.Where("group_id = ?", group) - } - if search != "" { - conn = conn.Where("`name` like ? or `description` like ?", "%"+search+"%", "%"+search+"%") - } - return conn.Count(&total).Order("sort ASC").Limit(size).Offset((page - 1) * size).Find(v).Error - }) - return total, list, err -} - -// QuerySubscribeList Get Subscribe List -func (m *customSubscribeModel) QuerySubscribeList(ctx context.Context) ([]*Subscribe, error) { - var list []*Subscribe - err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error { - conn = conn.Model(&Subscribe{}) - return conn.Where("`sell` = true").Order("sort ").Find(v).Error - }) - return list, err -} - -func (m *customSubscribeModel) QuerySubscribeIdsByServerIdAndServerGroupId(ctx context.Context, serverId, serverGroupId int64) ([]*Subscribe, error) { - var data []*Subscribe - err := m.QueryNoCacheCtx(ctx, &data, func(conn *gorm.DB, v interface{}) error { - return conn.Model(&Subscribe{}).Where("FIND_IN_SET(?, server)", serverId).Or("FIND_IN_SET(?, server_group)", serverGroupId).Find(v).Error - }) - return data, err -} - -// QuerySubscribeListByShow Get Subscribe List By Show -func (m *customSubscribeModel) QuerySubscribeListByShow(ctx context.Context) ([]*Subscribe, error) { - var list []*Subscribe - err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error { - conn = conn.Model(&Subscribe{}) - return conn.Where("`show` = true").Find(v).Error - }) - return list, err -} - func (m *customSubscribeModel) QuerySubscribeMinSortByIds(ctx context.Context, ids []int64) (int64, error) { var minSort int64 err := m.QueryNoCacheCtx(ctx, &minSort, func(conn *gorm.DB, v interface{}) error { @@ -101,14 +51,6 @@ func (m *customSubscribeModel) QuerySubscribeMinSortByIds(ctx context.Context, i return minSort, err } -func (m *customSubscribeModel) QuerySubscribeListByIds(ctx context.Context, ids []int64) ([]*Subscribe, error) { - var list []*Subscribe - err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error { - return conn.Model(&Subscribe{}).Where("id IN ?", ids).Find(v).Error - }) - return list, err -} - func (m *customSubscribeModel) ClearCache(ctx context.Context, ids ...int64) error { if len(ids) <= 0 { return nil @@ -124,3 +66,91 @@ func (m *customSubscribeModel) ClearCache(ctx context.Context, ids ...int64) err } return m.CachedConn.DelCacheCtx(ctx, cacheKeys...) } + +// FilterList Filter Subscribe List +func (m *customSubscribeModel) FilterList(ctx context.Context, params *FilterParams) (int64, []*Subscribe, error) { + if params == nil { + params = &FilterParams{} + } + params.Normalize() + + var list []*Subscribe + var total int64 + + // 构建查询函数 + buildQuery := func(conn *gorm.DB, lang string) *gorm.DB { + query := conn.Model(&Subscribe{}) + + if params.Search != "" { + s := "%" + params.Search + "%" + query = query.Where("`name` LIKE ? OR `description` LIKE ?", s, s) + } + if params.Show { + query = query.Where("`show` = true") + } + if params.Sell { + query = query.Where("`sell` = true") + } + + if len(params.Ids) > 0 { + query = query.Where("id IN ?", params.Ids) + } + if len(params.Node) > 0 { + query = query.Scopes(InSet("nodes", tool.Int64SliceToStringSlice(params.Node))) + } + + if len(params.Tags) > 0 { + query = query.Scopes(InSet("node_tags", params.Tags)) + } + if lang != "" { + query = query.Where("language = ?", lang) + } else if params.DefaultLanguage { + query = query.Where("language = ''") + } + + return query + } + + // 查询数据 + queryFunc := func(lang string) error { + return m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error { + query := buildQuery(conn, lang) + if err := query.Count(&total).Error; err != nil { + return err + } + return query.Order("sort ASC"). + Limit(params.Size). + Offset((params.Page - 1) * params.Size). + Find(v).Error + }) + } + + err := queryFunc(params.Language) + if err != nil { + return 0, nil, err + } + + // fallback 默认语言 + if params.DefaultLanguage && total == 0 { + err = queryFunc("") + if err != nil { + return 0, nil, err + } + } + + return total, list, nil +} + +func InSet(field string, values []string) func(db *gorm.DB) *gorm.DB { + return func(db *gorm.DB) *gorm.DB { + if len(values) == 0 { + return db + } + + query := db.Where("1=0") + for _, v := range values { + query = query.Or("FIND_IN_SET(?, "+field+")", v) + } + return query + } +} diff --git a/internal/model/subscribe/subscribe.go b/internal/model/subscribe/subscribe.go index 4261715..a80ea63 100644 --- a/internal/model/subscribe/subscribe.go +++ b/internal/model/subscribe/subscribe.go @@ -9,6 +9,7 @@ import ( type Subscribe struct { Id int64 `gorm:"primaryKey"` Name string `gorm:"type:varchar(255);not null;default:'';comment:Subscribe Name"` + Language string `gorm:"type:varchar(255);not null;default:'';comment:Language"` Description string `gorm:"type:text;comment:Subscribe Description"` UnitPrice int64 `gorm:"type:int;not null;default:0;comment:Unit Price"` UnitTime string `gorm:"type:varchar(255);not null;default:'';comment:Unit Time"` @@ -19,9 +20,8 @@ type Subscribe struct { SpeedLimit int64 `gorm:"type:int;not null;default:0;comment:Speed Limit"` DeviceLimit int64 `gorm:"type:int;not null;default:0;comment:Device Limit"` Quota int64 `gorm:"type:int;not null;default:0;comment:Quota"` - GroupId int64 `gorm:"type:bigint;comment:Group Id"` - ServerGroup string `gorm:"type:varchar(255);comment:Server Group"` - Server string `gorm:"type:varchar(255);comment:Server"` + Nodes string `gorm:"type:varchar(255);comment:Node Ids"` + NodeTags string `gorm:"type:varchar(255);comment:Node Tags"` Show *bool `gorm:"type:tinyint(1);not null;default:0;comment:Show portal page"` Sell *bool `gorm:"type:tinyint(1);not null;default:0;comment:Sell"` Sort int64 `gorm:"type:int;not null;default:0;comment:Sort"` diff --git a/internal/model/subscribeType/default.go b/internal/model/subscribeType/default.go deleted file mode 100644 index cf6d8bd..0000000 --- a/internal/model/subscribeType/default.go +++ /dev/null @@ -1,117 +0,0 @@ -package subscribeType - -import ( - "context" - "errors" - "fmt" - - "github.com/perfect-panel/server/pkg/cache" - "github.com/redis/go-redis/v9" - "gorm.io/gorm" -) - -var _ Model = (*customSubscribeTypeModel)(nil) -var ( - cacheSubscribeTypeIdPrefix = "cache:subscribeType:id:" -) - -type ( - Model interface { - subscribeTypeModel - customSubscribeTypeLogicModel - } - subscribeTypeModel interface { - Insert(ctx context.Context, data *SubscribeType) error - FindOne(ctx context.Context, id int64) (*SubscribeType, error) - Update(ctx context.Context, data *SubscribeType) error - Delete(ctx context.Context, id int64) error - Transaction(ctx context.Context, fn func(db *gorm.DB) error) error - } - - customSubscribeTypeModel struct { - *defaultSubscribeTypeModel - } - defaultSubscribeTypeModel struct { - cache.CachedConn - table string - } -) - -func newSubscribeTypeModel(db *gorm.DB, c *redis.Client) *defaultSubscribeTypeModel { - return &defaultSubscribeTypeModel{ - CachedConn: cache.NewConn(db, c), - table: "`SubscribeType`", - } -} - -//nolint:unused -func (m *defaultSubscribeTypeModel) batchGetCacheKeys(SubscribeTypes ...*SubscribeType) []string { - var keys []string - for _, subscribeType := range SubscribeTypes { - keys = append(keys, m.getCacheKeys(subscribeType)...) - } - return keys - -} -func (m *defaultSubscribeTypeModel) getCacheKeys(data *SubscribeType) []string { - if data == nil { - return []string{} - } - SubscribeTypeIdKey := fmt.Sprintf("%s%v", cacheSubscribeTypeIdPrefix, data.Id) - cacheKeys := []string{ - SubscribeTypeIdKey, - } - return cacheKeys -} - -func (m *defaultSubscribeTypeModel) Insert(ctx context.Context, data *SubscribeType) error { - err := m.ExecCtx(ctx, func(conn *gorm.DB) error { - return conn.Create(&data).Error - }, m.getCacheKeys(data)...) - return err -} - -func (m *defaultSubscribeTypeModel) FindOne(ctx context.Context, id int64) (*SubscribeType, error) { - SubscribeTypeIdKey := fmt.Sprintf("%s%v", cacheSubscribeTypeIdPrefix, id) - var resp SubscribeType - err := m.QueryCtx(ctx, &resp, SubscribeTypeIdKey, func(conn *gorm.DB, v interface{}) error { - return conn.Model(&SubscribeType{}).Where("`id` = ?", id).First(&resp).Error - }) - switch { - case err == nil: - return &resp, nil - default: - return nil, err - } -} - -func (m *defaultSubscribeTypeModel) Update(ctx context.Context, data *SubscribeType) error { - old, err := m.FindOne(ctx, data.Id) - if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - return err - } - err = m.ExecCtx(ctx, func(conn *gorm.DB) error { - db := conn - return db.Save(data).Error - }, m.getCacheKeys(old)...) - return err -} - -func (m *defaultSubscribeTypeModel) Delete(ctx context.Context, id int64) error { - data, err := m.FindOne(ctx, id) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil - } - return err - } - err = m.ExecCtx(ctx, func(conn *gorm.DB) error { - db := conn - return db.Delete(&SubscribeType{}, id).Error - }, m.getCacheKeys(data)...) - return err -} - -func (m *defaultSubscribeTypeModel) Transaction(ctx context.Context, fn func(db *gorm.DB) error) error { - return m.TransactCtx(ctx, fn) -} diff --git a/internal/model/subscribeType/model.go b/internal/model/subscribeType/model.go deleted file mode 100644 index 52e7e0f..0000000 --- a/internal/model/subscribeType/model.go +++ /dev/null @@ -1,16 +0,0 @@ -package subscribeType - -import ( - "github.com/redis/go-redis/v9" - "gorm.io/gorm" -) - -type customSubscribeTypeLogicModel interface { -} - -// NewModel returns a model for the database table. -func NewModel(conn *gorm.DB, c *redis.Client) Model { - return &customSubscribeTypeModel{ - defaultSubscribeTypeModel: newSubscribeTypeModel(conn, c), - } -} diff --git a/internal/model/subscribeType/subscribeType.go b/internal/model/subscribeType/subscribeType.go deleted file mode 100644 index c0a9d94..0000000 --- a/internal/model/subscribeType/subscribeType.go +++ /dev/null @@ -1,15 +0,0 @@ -package subscribeType - -import "time" - -type SubscribeType struct { - Id int64 `gorm:"primary_key"` - Name string `gorm:"type:varchar(50);default:'';not null;comment:订阅类型"` - Mark string `gorm:"type:varchar(255);default:'';not null;comment:订阅标识"` - CreatedAt time.Time `gorm:"<-:create;comment:创建时间"` - UpdatedAt time.Time `gorm:"comment:更新时间"` -} - -func (SubscribeType) TableName() string { - return "subscribe_type" -} diff --git a/internal/model/system/model.go b/internal/model/system/model.go index 60cef38..a7c28e1 100644 --- a/internal/model/system/model.go +++ b/internal/model/system/model.go @@ -19,6 +19,7 @@ type customSystemLogicModel interface { GetTosConfig(ctx context.Context) ([]*System, error) GetCurrencyConfig(ctx context.Context) ([]*System, error) GetVerifyCodeConfig(ctx context.Context) ([]*System, error) + GetLogConfig(ctx context.Context) ([]*System, error) UpdateNodeMultiplierConfig(ctx context.Context, config string) error FindNodeMultiplierConfig(ctx context.Context) (*System, error) } @@ -152,3 +153,12 @@ func (m *customSystemModel) GetVerifyCodeConfig(ctx context.Context) ([]*System, }) return configs, err } + +// GetLogConfig returns the log config. +func (m *customSystemModel) GetLogConfig(ctx context.Context) ([]*System, error) { + var configs []*System + err := m.QueryNoCacheCtx(ctx, &configs, func(conn *gorm.DB, v interface{}) error { + return conn.Where("`category` = ?", "log").Find(v).Error + }) + return configs, err +} diff --git a/internal/model/task/task.go b/internal/model/task/task.go index c30fee2..5c1b987 100644 --- a/internal/model/task/task.go +++ b/internal/model/task/task.go @@ -1,27 +1,151 @@ package task -import "time" +import ( + "encoding/json" + "time" +) -type EmailTask struct { - Id int64 `gorm:"column:id;primaryKey;autoIncrement;comment:ID"` - Subject string `gorm:"column:subject;type:varchar(255);not null;comment:Email Subject"` - Content string `gorm:"column:content;type:text;not null;comment:Email Content"` - Recipients string `gorm:"column:recipient;type:text;not null;comment:Email Recipient"` - Scope string `gorm:"column:scope;type:varchar(50);not null;comment:Email Scope"` - RegisterStartTime time.Time `gorm:"column:register_start_time;default:null;comment:Register Start Time"` - RegisterEndTime time.Time `gorm:"column:register_end_time;default:null;comment:Register End Time"` - Additional string `gorm:"column:additional;type:text;default:null;comment:Additional Information"` - Scheduled time.Time `gorm:"column:scheduled;not null;comment:Scheduled Time"` - Interval uint8 `gorm:"column:interval;not null;comment:Interval in Seconds"` - Limit uint64 `gorm:"column:limit;not null;comment:Daily send limit"` - Status uint8 `gorm:"column:status;not null;comment:Daily Status"` - Errors string `gorm:"column:errors;type:text;not null;comment:Errors"` - Total uint64 `gorm:"column:total;not null;default:0;comment:Total Number"` - Current uint64 `gorm:"column:current;not null;default:0;comment:Current Number"` - CreatedAt time.Time `gorm:"<-:create;comment:Creation Time"` - UpdatedAt time.Time `gorm:"comment:Update Time"` +type Type int8 + +const ( + Undefined Type = -1 + TypeEmail = iota + TypeQuota +) + +type Task struct { + Id int64 `gorm:"primaryKey;autoIncrement;comment:ID"` + Type int8 `gorm:"not null;comment:Task Type"` + Scope string `gorm:"type:text;comment:Task Scope"` + Content string `gorm:"type:text;comment:Task Content"` + Status int8 `gorm:"not null;default:0;comment:Task Status: 0: Pending, 1: In Progress, 2: Completed, 3: Failed"` + Errors string `gorm:"type:text;comment:Task Errors"` + Total uint64 `gorm:"column:total;not null;default:0;comment:Total Number"` + Current uint64 `gorm:"column:current;not null;default:0;comment:Current Number"` + CreatedAt time.Time `gorm:"<-:create;comment:Creation Time"` + UpdatedAt time.Time `gorm:"comment:Update Time"` } -func (EmailTask) TableName() string { - return "email_task" +func (Task) TableName() string { + return "task" +} + +type ScopeType int8 + +const ( + ScopeAll ScopeType = iota + 1 // All users + ScopeActive // Active users + ScopeExpired // Expired users + ScopeNone // No Subscribe + ScopeSkip // Skip user filtering +) + +func (t ScopeType) Int8() int8 { + return int8(t) +} + +type EmailScope struct { + Type int8 `gorm:"not null;comment:Scope Type"` + RegisterStartTime int64 `json:"register_start_time"` + RegisterEndTime int64 `json:"register_end_time"` + Recipients []string `json:"recipients"` // list of email addresses + Additional []string `json:"additional"` // additional email addresses + Scheduled int64 `json:"scheduled"` // scheduled time (unix timestamp) + Interval uint8 `json:"interval"` // interval in seconds + Limit uint64 `json:"limit"` // daily send limit +} + +func (s *EmailScope) Marshal() ([]byte, error) { + type Alias EmailScope + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(s), + }) +} + +func (s *EmailScope) Unmarshal(data []byte) error { + type Alias EmailScope + aux := (*Alias)(s) + return json.Unmarshal(data, &aux) +} + +type EmailContent struct { + Subject string `json:"subject"` + Content string `json:"content"` +} + +func (c *EmailContent) Marshal() ([]byte, error) { + type Alias EmailContent + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(c), + }) +} + +func (c *EmailContent) Unmarshal(data []byte) error { + type Alias EmailContent + aux := (*Alias)(c) + return json.Unmarshal(data, &aux) +} + +type QuotaScope struct { + Subscribers []int64 `json:"subscribers"` // Subscribe IDs + IsActive *bool `json:"is_active"` // filter by active status + StartTime int64 `json:"start_time"` // filter by subscription start time + EndTime int64 `json:"end_time"` // filter by subscription end time + Objects []int64 `json:"recipients"` // list of user subs IDs +} + +func (s *QuotaScope) Marshal() ([]byte, error) { + type Alias QuotaScope + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(s), + }) +} + +func (s *QuotaScope) Unmarshal(data []byte) error { + type Alias QuotaScope + aux := (*Alias)(s) + return json.Unmarshal(data, &aux) +} + +type QuotaContent struct { + ResetTraffic bool `json:"reset_traffic"` // whether to reset traffic + Days uint64 `json:"days,omitempty"` // days to add + GiftType uint8 `json:"gift_type,omitempty"` // 1: Fixed, 2: Ratio + GiftValue uint64 `json:"gift_value,omitempty"` // value of the gift type +} + +func (c *QuotaContent) Marshal() ([]byte, error) { + type Alias QuotaContent + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(c), + }) +} + +func (c *QuotaContent) Unmarshal(data []byte) error { + type Alias QuotaContent + aux := (*Alias)(c) + return json.Unmarshal(data, &aux) +} + +func ParseScopeType(t int8) ScopeType { + switch t { + case 1: + return ScopeAll + case 2: + return ScopeActive + case 3: + return ScopeExpired + case 4: + return ScopeNone + default: + return ScopeSkip + } } diff --git a/internal/model/user/default.go b/internal/model/user/default.go index 988d9e9..e2a326a 100644 --- a/internal/model/user/default.go +++ b/internal/model/user/default.go @@ -144,30 +144,10 @@ func (m *defaultUserModel) Delete(ctx context.Context, id int64, tx ...*gorm.DB) return err } - if err := db.Model(&BalanceLog{}).Where("`user_id` = ?", id).Delete(&BalanceLog{}).Error; err != nil { - return err - } - - if err := db.Model(&GiftAmountLog{}).Where("`user_id` = ?", id).Delete(&GiftAmountLog{}).Error; err != nil { - return err - } - - if err := db.Model(&LoginLog{}).Where("`user_id` = ?", id).Delete(&LoginLog{}).Error; err != nil { - return err - } - - if err := db.Model(&SubscribeLog{}).Where("`user_id` = ?", id).Delete(&SubscribeLog{}).Error; err != nil { - return err - } - if err := db.Model(&Device{}).Where("`user_id` = ?", id).Delete(&Device{}).Error; err != nil { return err } - if err := db.Model(&CommissionLog{}).Where("`user_id` = ?", id).Delete(&CommissionLog{}).Error; err != nil { - return err - } - return nil }) } diff --git a/internal/model/user/log.go b/internal/model/user/log.go deleted file mode 100644 index d3e1105..0000000 --- a/internal/model/user/log.go +++ /dev/null @@ -1,81 +0,0 @@ -package user - -import ( - "context" - - "github.com/pkg/errors" - "gorm.io/gorm" -) - -func (m *customUserModel) InsertSubscribeLog(ctx context.Context, log *SubscribeLog) error { - return m.ExecNoCacheCtx(ctx, func(conn *gorm.DB) error { - return conn.Create(log).Error - }) -} - -func (m *customUserModel) FilterSubscribeLogList(ctx context.Context, page, size int, filter *SubscribeLogFilterParams) ([]*SubscribeLog, int64, error) { - var list []*SubscribeLog - var total int64 - err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error { - query := conn.Model(&SubscribeLog{}) - if filter != nil { - if filter.UserId != 0 { - query = query.Where("user_id = ?", filter.UserId) - } - if filter.UserSubscribeId != 0 { - query = query.Where("user_subscribe_id = ?", filter.UserSubscribeId) - } - if filter.IP != "" { - query = query.Where("ip LIKE ?", "%"+filter.IP+"%") - } - if filter.Token != "" { - query = query.Where("token LIKE ?", "%"+filter.Token+"%") - } - if filter.UserAgent != "" { - query = query.Where("user_agent LIKE ?", "%"+filter.UserAgent+"%") - } - } - return query.Count(&total).Limit(size).Offset((page - 1) * size).Find(v).Error - }) - - if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - return nil, 0, err - } - - return list, total, nil -} - -func (m *customUserModel) InsertLoginLog(ctx context.Context, log *LoginLog) error { - return m.ExecNoCacheCtx(ctx, func(conn *gorm.DB) error { - return conn.Create(log).Error - }) -} - -func (m *customUserModel) FilterLoginLogList(ctx context.Context, page, size int, filter *LoginLogFilterParams) ([]*LoginLog, int64, error) { - var list []*LoginLog - var total int64 - err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error { - query := conn.Model(&LoginLog{}) - if filter != nil { - if filter.UserId != 0 { - query = query.Where("user_id = ?", filter.UserId) - } - if filter.IP != "" { - query = query.Where("ip LIKE ?", "%"+filter.IP+"%") - } - if filter.UserAgent != "" { - query = query.Where("user_agent LIKE ?", "%"+filter.UserAgent+"%") - } - if filter.Success != nil { - query = query.Where("success = ?", *filter.Success) - } - } - return query.Count(&total).Limit(size).Offset((page - 1) * size).Find(v).Error - }) - - if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - return nil, 0, err - } - - return list, total, nil -} diff --git a/internal/model/user/model.go b/internal/model/user/model.go index cc3d32c..3c5dff9 100644 --- a/internal/model/user/model.go +++ b/internal/model/user/model.go @@ -2,11 +2,12 @@ package user import ( "context" - "errors" "fmt" "time" + "github.com/perfect-panel/server/internal/model/order" "github.com/perfect-panel/server/internal/model/subscribe" + "github.com/redis/go-redis/v9" "gorm.io/gorm" ) @@ -76,7 +77,6 @@ type customUserLogicModel interface { QueryUserSubscribe(ctx context.Context, userId int64, status ...int64) ([]*SubscribeDetails, error) FindOneSubscribeDetailsById(ctx context.Context, id int64) (*SubscribeDetails, error) FindOneUserSubscribe(ctx context.Context, id int64) (*SubscribeDetails, error) - InsertBalanceLog(ctx context.Context, data *BalanceLog, tx ...*gorm.DB) error FindUsersSubscribeBySubscribeId(ctx context.Context, subscribeId int64) ([]*Subscribe, error) UpdateUserSubscribeWithTraffic(ctx context.Context, id, download, upload int64, tx ...*gorm.DB) error QueryResisterUserTotalByDate(ctx context.Context, date time.Time) (int64, error) @@ -85,7 +85,6 @@ type customUserLogicModel interface { QueryAdminUsers(ctx context.Context) ([]*User, error) UpdateUserCache(ctx context.Context, data *User) error UpdateUserSubscribeCache(ctx context.Context, data *Subscribe) error - InsertCommissionLog(ctx context.Context, data *CommissionLog, tx ...*gorm.DB) error QueryActiveSubscriptions(ctx context.Context, subscribeId ...int64) (map[int64]int64, error) FindUserAuthMethods(ctx context.Context, userId int64) ([]*AuthMethods, error) InsertUserAuthMethods(ctx context.Context, data *AuthMethods, tx ...*gorm.DB) error @@ -101,19 +100,8 @@ type customUserLogicModel interface { FindOneDeviceByIdentifier(ctx context.Context, id string) (*Device, error) DeleteDevice(ctx context.Context, id int64, tx ...*gorm.DB) error - InsertSubscribeLog(ctx context.Context, log *SubscribeLog) error - FilterSubscribeLogList(ctx context.Context, page, size int, filter *SubscribeLogFilterParams) ([]*SubscribeLog, int64, error) - InsertLoginLog(ctx context.Context, log *LoginLog) error - FilterLoginLogList(ctx context.Context, page, size int, filter *LoginLogFilterParams) ([]*LoginLog, int64, error) - ClearSubscribeCache(ctx context.Context, data ...*Subscribe) error - clearUserCache(ctx context.Context, data ...*User) error - - InsertResetSubscribeLog(ctx context.Context, log *ResetSubscribeLog, tx ...*gorm.DB) error - UpdateResetSubscribeLog(ctx context.Context, log *ResetSubscribeLog, tx ...*gorm.DB) error - FindResetSubscribeLog(ctx context.Context, id int64) (*ResetSubscribeLog, error) - DeleteResetSubscribeLog(ctx context.Context, id int64, tx ...*gorm.DB) error - FilterResetSubscribeLogList(ctx context.Context, filter *FilterResetSubscribeLogParams) ([]*ResetSubscribeLog, int64, error) + ClearUserCache(ctx context.Context, data ...*User) error QueryDailyUserStatisticsList(ctx context.Context, date time.Time) ([]UserStatisticsWithDate, error) QueryMonthlyUserStatisticsList(ctx context.Context, date time.Time) ([]UserStatisticsWithDate, error) @@ -180,27 +168,6 @@ func (m *customUserModel) BatchDeleteUser(ctx context.Context, ids []int64, tx . }, m.batchGetCacheKeys(users...)...) } -// InsertBalanceLog insert BalanceLog into the database. -func (m *customUserModel) InsertBalanceLog(ctx context.Context, data *BalanceLog, tx ...*gorm.DB) error { - return m.ExecNoCacheCtx(ctx, func(conn *gorm.DB) error { - if len(tx) > 0 { - conn = tx[0] - } - return conn.Create(data).Error - }) -} - -// FindUserBalanceLogList returns a list of records that meet the conditions. -func (m *customUserModel) FindUserBalanceLogList(ctx context.Context, userId int64, page, size int) ([]*BalanceLog, int64, error) { - var list []*BalanceLog - var total int64 - err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error { - - return conn.Model(&BalanceLog{}).Where("`user_id` = ?", userId).Count(&total).Limit(size).Offset((page - 1) * size).Find(&list).Error - }) - return list, total, err -} - func (m *customUserModel) UpdateUserSubscribeWithTraffic(ctx context.Context, id, download, upload int64, tx ...*gorm.DB) error { sub, err := m.FindOneSubscribe(ctx, id) if err != nil { @@ -265,15 +232,6 @@ func (m *customUserModel) UpdateUserCache(ctx context.Context, data *User) error return m.ClearUserCache(ctx, data) } -func (m *customUserModel) InsertCommissionLog(ctx context.Context, data *CommissionLog, tx ...*gorm.DB) error { - return m.ExecNoCacheCtx(ctx, func(conn *gorm.DB) error { - if len(tx) > 0 { - conn = tx[0] - } - return conn.Model(&CommissionLog{}).Create(data).Error - }) -} - func (m *customUserModel) FindOneByReferCode(ctx context.Context, referCode string) (*User, error) { var data User err := m.QueryNoCacheCtx(ctx, &data, func(conn *gorm.DB, v interface{}) error { @@ -290,121 +248,77 @@ func (m *customUserModel) FindOneSubscribeDetailsById(ctx context.Context, id in return &data, err } -func (m *customUserModel) InsertResetSubscribeLog(ctx context.Context, log *ResetSubscribeLog, tx ...*gorm.DB) error { - return m.ExecNoCacheCtx(ctx, func(conn *gorm.DB) error { - if len(tx) > 0 { - conn = tx[0] - } - return conn.Model(&ResetSubscribeLog{}).Create(log).Error - }) -} - -func (m *customUserModel) UpdateResetSubscribeLog(ctx context.Context, log *ResetSubscribeLog, tx ...*gorm.DB) error { - return m.ExecNoCacheCtx(ctx, func(conn *gorm.DB) error { - if len(tx) > 0 { - conn = tx[0] - } - return conn.Model(&ResetSubscribeLog{}).Where("id = ?", log.Id).Updates(log).Error - }) -} - -func (m *customUserModel) FindResetSubscribeLog(ctx context.Context, id int64) (*ResetSubscribeLog, error) { - var data ResetSubscribeLog - err := m.QueryNoCacheCtx(ctx, &data, func(conn *gorm.DB, v interface{}) error { - return conn.Model(&ResetSubscribeLog{}).Where("id = ?", id).First(&data).Error - }) - return &data, err -} - -func (m *customUserModel) DeleteResetSubscribeLog(ctx context.Context, id int64, tx ...*gorm.DB) error { - return m.ExecNoCacheCtx(ctx, func(conn *gorm.DB) error { - if len(tx) > 0 { - conn = tx[0] - } - return conn.Model(&ResetSubscribeLog{}).Where("id = ?", id).Delete(&ResetSubscribeLog{}).Error - }) -} - -func (m *customUserModel) FilterResetSubscribeLogList(ctx context.Context, filter *FilterResetSubscribeLogParams) ([]*ResetSubscribeLog, int64, error) { - if filter == nil { - return nil, 0, errors.New("filter params is nil") - } - - var list []*ResetSubscribeLog - var total int64 - - err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error { - query := conn.Model(&ResetSubscribeLog{}) - - // 应用筛选条件 - if filter.UserId != 0 { - query = query.Where("user_id = ?", filter.UserId) - } - if filter.UserSubscribeId != 0 { - query = query.Where("user_subscribe_id = ?", filter.UserSubscribeId) - } - if filter.Type != 0 { - query = query.Where("type = ?", filter.Type) - } - if filter.OrderNo != "" { - query = query.Where("order_no = ?", filter.OrderNo) - } - - // 计算总数 - if err := query.Count(&total).Error; err != nil { - return err - } - - // 应用分页 - if filter.Page > 0 && filter.Size > 0 { - query = query.Offset((filter.Page - 1) * filter.Size) - } - if filter.Size > 0 { - query = query.Limit(filter.Size) - } - - return query.Find(&list).Error - }) - - return list, total, err -} - // QueryDailyUserStatisticsList Query daily user statistics list for the current month (from 1st to current date) func (m *customUserModel) QueryDailyUserStatisticsList(ctx context.Context, date time.Time) ([]UserStatisticsWithDate, error) { var results []UserStatisticsWithDate + err := m.QueryNoCacheCtx(ctx, &results, func(conn *gorm.DB, v interface{}) error { firstDay := time.Date(date.Year(), date.Month(), 1, 0, 0, 0, 0, date.Location()) + + // 子查询:统计每天的新用户订单数量 + newOrderSub := conn.Model(&order.Order{}). + Select("DATE_FORMAT(created_at, '%Y-%m-%d') AS date, COUNT(DISTINCT user_id) AS new_order_users"). + Where("is_new = 1 AND created_at BETWEEN ? AND ? AND status IN ?", firstDay, date, []int64{2, 5}). + Group("DATE_FORMAT(created_at, '%Y-%m-%d')") + + // 子查询:统计每天的续费订单数量 + renewalOrderSub := conn.Model(&order.Order{}). + Select("DATE_FORMAT(created_at, '%Y-%m-%d') AS date, COUNT(DISTINCT user_id) AS renewal_order_users"). + Where("is_new = 0 AND created_at BETWEEN ? AND ? AND status IN ?", firstDay, date, []int64{2, 5}). + Group("DATE_FORMAT(created_at, '%Y-%m-%d')") + return conn.Model(&User{}). - Select( - "DATE(created_at) as date, "+ - "COUNT(*) as register, "+ - "0 as new_order_users, "+ - "0 as renewal_order_users", - ). - Where("created_at BETWEEN ? AND ?", firstDay, date). - Group("DATE(created_at)"). + Select(` + DATE_FORMAT(user.created_at, '%Y-%m-%d') AS date, + COUNT(*) AS register, + IFNULL(MAX(n.new_order_users), 0) AS new_order_users, + IFNULL(MAX(r.renewal_order_users), 0) AS renewal_order_users + `). + Joins("LEFT JOIN (?) AS n ON DATE_FORMAT(user.created_at, '%Y-%m-%d') = n.date", newOrderSub). + Joins("LEFT JOIN (?) AS r ON DATE_FORMAT(user.created_at, '%Y-%m-%d') = r.date", renewalOrderSub). + Where("user.created_at BETWEEN ? AND ?", firstDay, date). + Group("DATE_FORMAT(user.created_at, '%Y-%m-%d')"). Order("date ASC"). Scan(v).Error }) + return results, err } // QueryMonthlyUserStatisticsList Query monthly user statistics list for the past 6 months func (m *customUserModel) QueryMonthlyUserStatisticsList(ctx context.Context, date time.Time) ([]UserStatisticsWithDate, error) { var results []UserStatisticsWithDate + err := m.QueryNoCacheCtx(ctx, &results, func(conn *gorm.DB, v interface{}) error { + // 获取 6 个月前的日期 sixMonthsAgo := date.AddDate(0, -5, 0) + + // 子查询:每月新订单用户数量 + newOrderSub := conn.Model(&order.Order{}). + Select("DATE_FORMAT(created_at, '%Y-%m') AS date, COUNT(DISTINCT user_id) AS new_order_users"). + Where("is_new = 1 AND created_at >= ? AND status IN ?", sixMonthsAgo, []int64{2, 5}). + Group("DATE_FORMAT(created_at, '%Y-%m')") + + // 子查询:每月续费订单用户数量 + renewalOrderSub := conn.Model(&order.Order{}). + Select("DATE_FORMAT(created_at, '%Y-%m') AS date, COUNT(DISTINCT user_id) AS renewal_order_users"). + Where("is_new = 0 AND created_at >= ? AND status IN ?", sixMonthsAgo, []int64{2, 5}). + Group("DATE_FORMAT(created_at, '%Y-%m')") + return conn.Model(&User{}). - Select( - "DATE_FORMAT(created_at, '%Y-%m') as date, "+ - "COUNT(*) as register, "+ - "0 as new_order_users, "+ - "0 as renewal_order_users", - ). - Where("created_at >= ?", sixMonthsAgo). - Group("DATE_FORMAT(created_at, '%Y-%m')"). + Select(` + DATE_FORMAT(user.created_at, '%Y-%m') AS date, + COUNT(*) AS register, + IFNULL(MAX(n.new_order_users), 0) AS new_order_users, + IFNULL(MAX(r.renewal_order_users), 0) AS renewal_order_users + `). + Joins("LEFT JOIN (?) AS n ON DATE_FORMAT(user.created_at, '%Y-%m') = n.date", newOrderSub). + Joins("LEFT JOIN (?) AS r ON DATE_FORMAT(user.created_at, '%Y-%m') = r.date", renewalOrderSub). + Where("user.created_at >= ?", sixMonthsAgo). + Group("DATE_FORMAT(user.created_at, '%Y-%m')"). Order("date ASC"). Scan(v).Error }) + return results, err } diff --git a/internal/model/user/subscribe.go b/internal/model/user/subscribe.go index cdf17af..1113f30 100644 --- a/internal/model/user/subscribe.go +++ b/internal/model/user/subscribe.go @@ -60,7 +60,13 @@ func (m *defaultUserModel) FindOneSubscribe(ctx context.Context, id int64) (*Sub func (m *defaultUserModel) FindUsersSubscribeBySubscribeId(ctx context.Context, subscribeId int64) ([]*Subscribe, error) { var data []*Subscribe err := m.QueryNoCacheCtx(ctx, &data, func(conn *gorm.DB, v interface{}) error { - return conn.Model(&Subscribe{}).Where("subscribe_id = ? AND `status` IN ?", subscribeId, []int64{1, 0}).Find(&data).Error + err := conn.Model(&Subscribe{}).Where("subscribe_id = ? AND `status` IN ?", subscribeId, []int64{1, 0}).Find(v).Error + + if err != nil { + return err + } + // update user subscribe status + return conn.Model(&Subscribe{}).Where("subscribe_id = ? AND `status` = ?", subscribeId, 0).Update("status", 1).Error }) return data, err } diff --git a/internal/model/user/user.go b/internal/model/user/user.go index 784d531..603f98e 100644 --- a/internal/model/user/user.go +++ b/internal/model/user/user.go @@ -11,7 +11,9 @@ type User struct { Balance int64 `gorm:"default:0;comment:User Balance"` // User Balance Amount ReferCode string `gorm:"type:varchar(20);default:'';comment:Referral Code"` RefererId int64 `gorm:"index:idx_referer;comment:Referrer ID"` - Commission int64 `gorm:"default:0;comment:Commission"` // Commission Amount + Commission int64 `gorm:"default:0;comment:Commission"` // Commission Amount + ReferralPercentage uint8 `gorm:"default:0;comment:Referral"` // Referral Percentage + OnlyFirstPurchase *bool `gorm:"default:true;not null;comment:Only First Purchase"` // Only First Purchase Referral GiftAmount int64 `gorm:"default:0;comment:User Gift Amount"` Enable *bool `gorm:"default:true;not null;comment:Is Account Enabled"` IsAdmin *bool `gorm:"default:false;not null;comment:Is Admin"` @@ -52,48 +54,6 @@ func (*Subscribe) TableName() string { return "user_subscribe" } -type BalanceLog struct { - Id int64 `gorm:"primaryKey"` - UserId int64 `gorm:"index:idx_user_id;not null;comment:User ID"` - Amount int64 `gorm:"not null;comment:Amount"` - Type uint8 `gorm:"type:tinyint(1);not null;comment:Type: 1: Recharge 2: Withdraw 3: Payment 4: Refund 5: Reward"` - OrderId int64 `gorm:"default:null;comment:Order ID"` - Balance int64 `gorm:"not null;comment:Balance"` - CreatedAt time.Time `gorm:"<-:create;comment:Creation Time"` -} - -func (BalanceLog) TableName() string { - return "user_balance_log" -} - -type GiftAmountLog struct { - Id int64 `gorm:"primaryKey"` - UserId int64 `gorm:"index:idx_user_id;not null;comment:User ID"` - UserSubscribeId int64 `gorm:"default:null;comment:Deduction User Subscribe ID"` - OrderNo string `gorm:"default:null;comment:Order No."` - Type uint8 `gorm:"type:tinyint(1);not null;comment:Type: 1: Increase 2: Reduce"` - Amount int64 `gorm:"not null;comment:Amount"` - Balance int64 `gorm:"not null;comment:Balance"` - Remark string `gorm:"type:varchar(255);default:'';comment:Remark"` - CreatedAt time.Time `gorm:"<-:create;comment:Creation Time"` -} - -func (GiftAmountLog) TableName() string { - return "user_gift_amount_log" -} - -type CommissionLog struct { - Id int64 `gorm:"primaryKey"` - UserId int64 `gorm:"index:idx_user_id;not null;comment:User ID"` - OrderNo string `gorm:"default:null;comment:Order No."` - Amount int64 `gorm:"not null;comment:Amount"` - CreatedAt time.Time `gorm:"<-:create;comment:Creation Time"` -} - -func (*CommissionLog) TableName() string { - return "user_commission_log" -} - type AuthMethods struct { Id int64 `gorm:"primaryKey"` UserId int64 `gorm:"index:idx_user_id;not null;comment:User ID"` @@ -138,58 +98,3 @@ type DeviceOnlineRecord struct { func (DeviceOnlineRecord) TableName() string { return "user_device_online_record" } - -type LoginLog struct { - Id int64 `gorm:"primaryKey"` - UserId int64 `gorm:"index:idx_user_id;not null;comment:User ID"` - LoginIP string `gorm:"type:varchar(255);not null;comment:Login IP"` - UserAgent string `gorm:"type:text;not null;comment:UserAgent"` - Success *bool `gorm:"default:false;not null;comment:Login Success"` - CreatedAt time.Time `gorm:"<-:create;comment:Creation Time"` -} - -func (LoginLog) TableName() string { - return "user_login_log" -} - -type SubscribeLog struct { - Id int64 `gorm:"primaryKey"` - UserId int64 `gorm:"index:idx_user_id;not null;comment:User ID"` - UserSubscribeId int64 `gorm:"index:idx_user_subscribe_id;not null;comment:User Subscribe ID"` - Token string `gorm:"type:varchar(255);not null;comment:Token"` - IP string `gorm:"type:varchar(255);not null;comment:IP"` - UserAgent string `gorm:"type:text;not null;comment:UserAgent"` - CreatedAt time.Time `gorm:"<-:create;comment:Creation Time"` -} - -func (SubscribeLog) TableName() string { - return "user_subscribe_log" -} - -const ( - ResetSubscribeTypeAuto uint8 = 1 - ResetSubscribeTypeAdvance uint8 = 2 - ResetSubscribeTypePaid uint8 = 3 -) - -type FilterResetSubscribeLogParams struct { - Page int - Size int - Type uint8 - UserId int64 - OrderNo string - UserSubscribeId int64 -} - -type ResetSubscribeLog struct { - Id int64 `gorm:"primaryKey"` - UserId int64 `gorm:"type:bigint;index:idx_user_id;not null;comment:User ID"` - Type uint8 `gorm:"type:tinyint(1);not null;comment:Type: 1: Auto 2: Advance 3: Paid"` - OrderNo string `gorm:"type:varchar(255);default:null;comment:Order No."` - UserSubscribeId int64 `gorm:"type:bigint;index:idx_user_subscribe_id;not null;comment:User Subscribe ID"` - CreatedAt time.Time `gorm:"<-:create;comment:Creation Time"` -} - -func (ResetSubscribeLog) TableName() string { - return "user_reset_subscribe_log" -} diff --git a/internal/svc/serviceContext.go b/internal/svc/serviceContext.go index 838e8e9..184dc69 100644 --- a/internal/svc/serviceContext.go +++ b/internal/svc/serviceContext.go @@ -4,25 +4,19 @@ import ( "context" "github.com/perfect-panel/server/internal/model/client" + "github.com/perfect-panel/server/internal/model/node" "github.com/perfect-panel/server/pkg/device" - "github.com/perfect-panel/server/internal/model/ads" - "github.com/perfect-panel/server/internal/model/cache" - - tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" - "github.com/hibiken/asynq" "github.com/perfect-panel/server/internal/config" + "github.com/perfect-panel/server/internal/model/ads" "github.com/perfect-panel/server/internal/model/announcement" - "github.com/perfect-panel/server/internal/model/application" "github.com/perfect-panel/server/internal/model/auth" "github.com/perfect-panel/server/internal/model/coupon" "github.com/perfect-panel/server/internal/model/document" "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/internal/model/order" "github.com/perfect-panel/server/internal/model/payment" - "github.com/perfect-panel/server/internal/model/server" "github.com/perfect-panel/server/internal/model/subscribe" - "github.com/perfect-panel/server/internal/model/subscribeType" "github.com/perfect-panel/server/internal/model/system" "github.com/perfect-panel/server/internal/model/ticket" "github.com/perfect-panel/server/internal/model/traffic" @@ -30,33 +24,35 @@ import ( "github.com/perfect-panel/server/pkg/limit" "github.com/perfect-panel/server/pkg/nodeMultiplier" "github.com/perfect-panel/server/pkg/orm" + + tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" + "github.com/hibiken/asynq" "github.com/redis/go-redis/v9" "gorm.io/gorm" ) type ServiceContext struct { - DB *gorm.DB - Redis *redis.Client - Config config.Config - Queue *asynq.Client - NodeCache *cache.NodeCacheClient - AuthModel auth.Model - AdsModel ads.Model - LogModel log.Model - UserModel user.Model - OrderModel order.Model - ClientModel client.Model - TicketModel ticket.Model - ServerModel server.Model - SystemModel system.Model - CouponModel coupon.Model - PaymentModel payment.Model - DocumentModel document.Model - SubscribeModel subscribe.Model - TrafficLogModel traffic.Model - ApplicationModel application.Model - AnnouncementModel announcement.Model - SubscribeTypeModel subscribeType.Model + DB *gorm.DB + Redis *redis.Client + Config config.Config + Queue *asynq.Client + //NodeCache *cache.NodeCacheClient + AuthModel auth.Model + AdsModel ads.Model + LogModel log.Model + NodeModel node.Model + UserModel user.Model + OrderModel order.Model + ClientModel client.Model + TicketModel ticket.Model + //ServerModel server.Model + SystemModel system.Model + CouponModel coupon.Model + PaymentModel payment.Model + DocumentModel document.Model + SubscribeModel subscribe.Model + TrafficLogModel traffic.Model + AnnouncementModel announcement.Model Restart func() error TelegramBot *tgbotapi.BotAPI @@ -86,27 +82,27 @@ func NewServiceContext(c config.Config) *ServiceContext { } authLimiter := limit.NewPeriodLimit(86400, 15, rds, config.SendCountLimitKeyPrefix, limit.Align()) srv := &ServiceContext{ - DB: db, - Redis: rds, - Config: c, - Queue: NewAsynqClient(c), - NodeCache: cache.NewNodeCacheClient(rds), - AuthLimiter: authLimiter, - AdsModel: ads.NewModel(db, rds), - LogModel: log.NewModel(db), - AuthModel: auth.NewModel(db, rds), - UserModel: user.NewModel(db, rds), - OrderModel: order.NewModel(db, rds), - ClientModel: client.NewSubscribeApplicationModel(db), - TicketModel: ticket.NewModel(db, rds), - ServerModel: server.NewModel(db, rds), + DB: db, + Redis: rds, + Config: c, + Queue: NewAsynqClient(c), + //NodeCache: cache.NewNodeCacheClient(rds), + AuthLimiter: authLimiter, + AdsModel: ads.NewModel(db, rds), + LogModel: log.NewModel(db), + NodeModel: node.NewModel(db, rds), + AuthModel: auth.NewModel(db, rds), + UserModel: user.NewModel(db, rds), + OrderModel: order.NewModel(db, rds), + ClientModel: client.NewSubscribeApplicationModel(db), + TicketModel: ticket.NewModel(db, rds), + //ServerModel: server.NewModel(db, rds), SystemModel: system.NewModel(db, rds), CouponModel: coupon.NewModel(db, rds), PaymentModel: payment.NewModel(db, rds), DocumentModel: document.NewModel(db, rds), SubscribeModel: subscribe.NewModel(db, rds), TrafficLogModel: traffic.NewModel(db), - ApplicationModel: application.NewModel(db, rds), AnnouncementModel: announcement.NewModel(db, rds), } srv.DeviceManager = NewDeviceManager(srv) diff --git a/internal/types/types.go b/internal/types/types.go index abbf554..8d4766e 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -37,80 +37,6 @@ type AnyTLS struct { SecurityConfig SecurityConfig `json:"security_config"` } -type AppAuthCheckRequest struct { - Method string `json:"method" validate:"required" validate:"required,oneof=device email mobile"` - Account string `json:"account"` - Identifier string `json:"identifier" validate:"required"` - UserAgent string `json:"user_agent" validate:"required,oneof=windows mac linux android ios harmony"` - AreaCode string `json:"area_code"` -} - -type AppAuthCheckResponse struct { - Status bool -} - -type AppAuthRequest struct { - Method string `json:"method" validate:"required" validate:"required,oneof=device email mobile"` - Account string `json:"account"` - Password string `json:"password"` - Identifier string `json:"identifier" validate:"required"` - UserAgent string `json:"user_agent" validate:"required,oneof=windows mac linux android ios harmony"` - Code string `json:"code"` - Invite string `json:"invite"` - AreaCode string `json:"area_code"` - CfToken string `json:"cf_token,optional"` -} - -type AppAuthRespone struct { - Token string `json:"token"` -} - -type AppConfigRequest struct { - UserAgent string `json:"user_agent" validate:"required,oneof=windows mac linux android ios harmony"` -} - -type AppConfigResponse struct { - EncryptionKey string `json:"encryption_key"` - EncryptionMethod string `json:"encryption_method"` - Domains []string `json:"domains"` - StartupPicture string `json:"startup_picture"` - StartupPictureSkipTime int64 `json:"startup_picture_skip_time"` - Application AppInfo `json:"applications"` - OfficialEmail string `json:"official_email"` - OfficialWebsite string `json:"official_website"` - OfficialTelegram string `json:"official_telegram"` - OfficialTelephone string `json:"official_telephone"` - InvitationLink string `json:"invitation_link"` - KrWebsiteId string `json:"kr_website_id"` -} - -type AppInfo struct { - Id int64 `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - Url string `json:"url"` - Version string `json:"version"` - VersionDescription string `json:"version_description"` - IsDefault bool `json:"is_default"` -} - -type AppRuleGroupListResponse struct { - Total int64 `json:"total"` - List []ServerRuleGroup `json:"list"` -} - -type AppSendCodeRequest struct { - Method string `json:"method" validate:"required" validate:"required,oneof=email mobile"` - Account string `json:"account"` - AreaCode string `json:"area_code"` - CfToken string `json:"cf_token,optional"` -} - -type AppSendCodeRespone struct { - Status bool `json:"status"` - Code string `json:"code,omitempty"` -} - type AppUserSubcbribe struct { Id int64 `json:"id"` Name string `json:"name"` @@ -145,22 +71,6 @@ type AppUserSubscbribeNode struct { Download int64 `json:"download"` } -type AppUserSubscbribeNodeRequest struct { - Id int64 `form:"id" validate:"required"` -} - -type AppUserSubscbribeNodeResponse struct { - List []AppUserSubscbribeNode `json:"list"` -} - -type AppUserSubscbribeResponse struct { - List []AppUserSubcbribe `json:"list"` -} - -type AppUserSubscribeRequest struct { - ContainsNodes *bool `form:"contains_nodes"` -} - type AppleLoginCallbackRequest struct { Code string `form:"code"` IDToken string `form:"id_token"` @@ -175,15 +85,6 @@ type Application struct { SubscribeType string `json:"subscribe_type"` } -type ApplicationConfig struct { - AppId int64 `json:"app_id"` - EncryptionKey string `json:"encryption_key"` - EncryptionMethod string `json:"encryption_method"` - Domains []string `json:"domains" validate:"required"` - StartupPicture string `json:"startup_picture"` - StartupPictureSkipTime int64 `json:"startup_picture_skip_time"` -} - type ApplicationPlatform struct { IOS []*ApplicationVersion `json:"ios,omitempty"` MacOS []*ApplicationVersion `json:"macos,omitempty"` @@ -227,6 +128,15 @@ type AuthMethodConfig struct { Enabled bool `json:"enabled"` } +type BalanceLog struct { + Type uint16 `json:"type"` + UserId int64 `json:"user_id"` + Amount int64 `json:"amount"` + OrderNo string `json:"order_no,omitempty"` + Balance int64 `json:"balance"` + Timestamp int64 `json:"timestamp"` +} + type BatchDeleteCouponRequest struct { Ids []int64 `json:"ids" validate:"required"` } @@ -235,14 +145,6 @@ type BatchDeleteDocumentRequest struct { Ids []int64 `json:"ids" validate:"required"` } -type BatchDeleteNodeGroupRequest struct { - Ids []int64 `json:"ids" validate:"required"` -} - -type BatchDeleteNodeRequest struct { - Ids []int64 `json:"ids" validate:"required"` -} - type BatchDeleteSubscribeGroupRequest struct { Ids []int64 `json:"ids" validate:"required"` } @@ -260,7 +162,7 @@ type BatchSendEmailTask struct { Subject string `json:"subject"` Content string `json:"content"` Recipients string `json:"recipients"` - Scope string `json:"scope"` + Scope int8 `json:"scope"` RegisterStartTime int64 `json:"register_start_time"` RegisterEndTime int64 `json:"register_end_time"` Additional string `json:"additional"` @@ -329,17 +231,11 @@ type CloseOrderRequest struct { } type CommissionLog struct { - Id int64 `json:"id"` + Type uint16 `json:"type"` UserId int64 `json:"user_id"` - OrderNo string `json:"order_no"` Amount int64 `json:"amount"` - CreatedAt int64 `json:"created_at"` -} - -type ConnectionRecords struct { - CurrentContinuousDays int64 `json:"current_continuous_days"` - HistoryContinuousDays int64 `json:"history_continuous_days"` - LongestSingleConnection int64 `json:"longest_single_connection"` + OrderNo string `json:"order_no"` + Timestamp int64 `json:"timestamp"` } type Coupon struct { @@ -375,27 +271,10 @@ type CreateAnnouncementRequest struct { Content string `json:"content" validate:"required"` } -type CreateApplicationRequest struct { - Icon string `json:"icon"` - Name string `json:"name"` - Description string `json:"description"` - SubscribeType string `json:"subscribe_type"` - Platform ApplicationPlatform `json:"platform"` -} - -type CreateApplicationVersionRequest struct { - Url string `json:"url"` - Version string `json:"version" validate:"required"` - Description string `json:"description"` - Platform string `json:"platform" validate:"required,oneof=windows mac linux android ios harmony"` - IsDefault bool `json:"is_default"` - ApplicationId int64 `json:"application_id" validate:"required"` -} - type CreateBatchSendEmailTaskRequest struct { Subject string `json:"subject"` Content string `json:"content"` - Scope string `json:"scope"` + Scope int8 `json:"scope"` RegisterStartTime int64 `json:"register_start_time,omitempty"` RegisterEndTime int64 `json:"register_end_time,omitempty"` Additional string `json:"additional,omitempty"` @@ -425,26 +304,14 @@ type CreateDocumentRequest struct { Show *bool `json:"show"` } -type CreateNodeGroupRequest struct { - Name string `json:"name" validate:"required"` - Description string `json:"description"` -} - type CreateNodeRequest struct { - Name string `json:"name" validate:"required"` - Tags []string `json:"tags"` - Country string `json:"country"` - City string `json:"city"` - ServerAddr string `json:"server_addr" validate:"required"` - RelayMode string `json:"relay_mode"` - RelayNode []NodeRelay `json:"relay_node"` - SpeedLimit int `json:"speed_limit"` - TrafficRatio float32 `json:"traffic_ratio"` - GroupId int64 `json:"group_id"` - Protocol string `json:"protocol" validate:"required"` - Config interface{} `json:"config" validate:"required"` - Enable *bool `json:"enable"` - Sort int64 `json:"sort"` + Name string `json:"name"` + Tags []string `json:"tags,omitempty"` + Port uint16 `json:"port"` + Address string `json:"address"` + ServerId int64 `json:"server_id"` + Protocol string `json:"protocol"` + Enabled *bool `json:"enabled"` } type CreateOrderRequest struct { @@ -477,14 +344,25 @@ type CreatePaymentMethodRequest struct { Enable *bool `json:"enable" validate:"required"` } -type CreateRuleGroupRequest struct { - Name string `json:"name" validate:"required"` - Icon string `json:"icon"` - Type string `json:"type"` - Tags []string `json:"tags"` - Rules string `json:"rules"` - Default bool `json:"default"` - Enable bool `json:"enable"` +type CreateQuotaTaskRequest struct { + Subscribers []int64 `json:"subscribers"` + IsActive *bool `json:"is_active"` + StartTime int64 `json:"start_time"` + EndTime int64 `json:"end_time"` + ResetTraffic bool `json:"reset_traffic"` + Days uint64 `json:"days"` + GiftType uint8 `json:"gift_type"` + GiftValue uint64 `json:"gift_value"` +} + +type CreateServerRequest struct { + Name string `json:"name"` + Country string `json:"country,omitempty"` + City string `json:"city,omitempty"` + Ratio float32 `json:"ratio"` + Address string `json:"address"` + Sort int `json:"sort,omitempty"` + Protocols []Protocol `json:"protocols"` } type CreateSubscribeApplicationRequest struct { @@ -506,6 +384,7 @@ type CreateSubscribeGroupRequest struct { type CreateSubscribeRequest struct { Name string `json:"name" validate:"required"` + Language string `json:"language"` Description string `json:"description"` UnitPrice int64 `json:"unit_price"` UnitTime string `json:"unit_time"` @@ -516,9 +395,8 @@ type CreateSubscribeRequest struct { SpeedLimit int64 `json:"speed_limit"` DeviceLimit int64 `json:"device_limit"` Quota int64 `json:"quota"` - GroupId int64 `json:"group_id"` - ServerGroup []int64 `json:"server_group"` - Server []int64 `json:"server"` + Nodes []int64 `json:"nodes"` + NodeTags []string `json:"node_tags"` Show *bool `json:"show"` Sell *bool `json:"sell"` DeductionRatio int64 `json:"deduction_ratio"` @@ -541,18 +419,20 @@ type CreateUserAuthMethodRequest struct { } type CreateUserRequest struct { - Email string `json:"email"` - Telephone string `json:"telephone"` - TelephoneAreaCode string `json:"telephone_area_code"` - Password string `json:"password"` - ProductId int64 `json:"product_id"` - Duration int64 `json:"duration"` - RefererUser string `json:"referer_user"` - ReferCode string `json:"refer_code"` - Balance int64 `json:"balance"` - Commission int64 `json:"commission"` - GiftAmount int64 `json:"gift_amount"` - IsAdmin bool `json:"is_admin"` + Email string `json:"email"` + Telephone string `json:"telephone"` + TelephoneAreaCode string `json:"telephone_area_code"` + Password string `json:"password"` + ProductId int64 `json:"product_id"` + Duration int64 `json:"duration"` + ReferralPercentage uint8 `json:"referral_percentage"` + OnlyFirstPurchase bool `json:"only_first_purchase"` + RefererUser string `json:"referer_user"` + ReferCode string `json:"refer_code"` + Balance int64 `json:"balance"` + Commission int64 `json:"commission"` + GiftAmount int64 `json:"gift_amount"` + IsAdmin bool `json:"is_admin"` } type CreateUserSubscribeRequest struct { @@ -585,11 +465,6 @@ type CurrencyConfig struct { CurrencySymbol string `json:"currency_symbol"` } -type DeleteAccountRequest struct { - Method string `json:"method" validate:"required" validate:"required,oneof=email telephone device"` - Code string `json:"code"` -} - type DeleteAdsRequest struct { Id int64 `json:"id"` } @@ -598,14 +473,6 @@ type DeleteAnnouncementRequest struct { Id int64 `json:"id" validate:"required"` } -type DeleteApplicationRequest struct { - Id int64 `json:"id" validate:"required"` -} - -type DeleteApplicationVersionRequest struct { - Id int64 `json:"id" validate:"required"` -} - type DeleteCouponRequest struct { Id int64 `json:"id" validate:"required"` } @@ -614,20 +481,16 @@ type DeleteDocumentRequest struct { Id int64 `json:"id" validate:"required"` } -type DeleteNodeGroupRequest struct { - Id int64 `json:"id" validate:"required"` -} - type DeleteNodeRequest struct { - Id int64 `json:"id" validate:"required"` + Id int64 `json:"id"` } type DeletePaymentMethodRequest struct { Id int64 `json:"id" validate:"required"` } -type DeleteRuleGroupRequest struct { - Id int64 `json:"id" validate:"required"` +type DeleteServerRequest struct { + Id int64 `json:"id"` } type DeleteSubscribeApplicationRequest struct { @@ -694,6 +557,149 @@ type EmailAuthticateConfig struct { DomainSuffixList string `json:"domain_suffix_list"` } +type FilterBalanceLogRequest struct { + FilterLogParams + UserId int64 `form:"user_id,optional"` +} + +type FilterBalanceLogResponse struct { + Total int64 `json:"total"` + List []BalanceLog `json:"list"` +} + +type FilterCommissionLogRequest struct { + FilterLogParams + UserId int64 `form:"user_id,optional"` +} + +type FilterCommissionLogResponse struct { + Total int64 `json:"total"` + List []CommissionLog `json:"list"` +} + +type FilterEmailLogResponse struct { + Total int64 `json:"total"` + List []MessageLog `json:"list"` +} + +type FilterGiftLogRequest struct { + FilterLogParams + UserId int64 `form:"user_id,optional"` +} + +type FilterGiftLogResponse struct { + Total int64 `json:"total"` + List []GiftLog `json:"list"` +} + +type FilterLogParams struct { + Page int `form:"page"` + Size int `form:"size"` + Date string `form:"date,optional"` + Search string `form:"search,optional"` +} + +type FilterLoginLogRequest struct { + FilterLogParams + UserId int64 `form:"user_id,optional"` +} + +type FilterLoginLogResponse struct { + Total int64 `json:"total"` + List []LoginLog `json:"list"` +} + +type FilterMobileLogResponse struct { + Total int64 `json:"total"` + List []MessageLog `json:"list"` +} + +type FilterNodeListRequest struct { + Page int `form:"page"` + Size int `form:"size"` + Search string `form:"search,omitempty"` +} + +type FilterNodeListResponse struct { + Total int64 `json:"total"` + List []Node `json:"list"` +} + +type FilterRegisterLogRequest struct { + FilterLogParams + UserId int64 `form:"user_id,optional"` +} + +type FilterRegisterLogResponse struct { + Total int64 `json:"total"` + List []RegisterLog `json:"list"` +} + +type FilterResetSubscribeLogRequest struct { + FilterLogParams + UserSubscribeId int64 `form:"user_subscribe_id,optional"` +} + +type FilterResetSubscribeLogResponse struct { + Total int64 `json:"total"` + List []ResetSubscribeLog `json:"list"` +} + +type FilterServerListRequest struct { + Page int `form:"page"` + Size int `form:"size"` + Search string `form:"search,omitempty"` +} + +type FilterServerListResponse struct { + Total int64 `json:"total"` + List []Server `json:"list"` +} + +type FilterServerTrafficLogRequest struct { + FilterLogParams + ServerId int64 `form:"server_id,optional"` +} + +type FilterServerTrafficLogResponse struct { + Total int64 `json:"total"` + List []ServerTrafficLog `json:"list"` +} + +type FilterSubscribeLogRequest struct { + FilterLogParams + UserId int64 `form:"user_id,optional"` + UserSubscribeId int64 `form:"user_subscribe_id,optional"` +} + +type FilterSubscribeLogResponse struct { + Total int64 `json:"total"` + List []SubscribeLog `json:"list"` +} + +type FilterSubscribeTrafficRequest struct { + FilterLogParams + UserId int64 `form:"user_id,optional"` + UserSubscribeId int64 `form:"user_subscribe_id,optional"` +} + +type FilterSubscribeTrafficResponse struct { + Total int64 `json:"total"` + List []UserSubscribeTrafficLog `json:"list"` +} + +type FilterTrafficLogDetailsRequest struct { + FilterLogParams + ServerId int64 `form:"server_id,optional"` + SubscribeId int64 `form:"subscribe_id,optional"` + UserId int64 `form:"user_id,optional"` +} + +type FilterTrafficLogDetailsResponse struct { + Total int64 `json:"total"` + List []TrafficLogDetails `json:"list"` +} + type Follow struct { Id int64 `json:"id"` TicketId int64 `json:"ticket_id"` @@ -746,11 +752,6 @@ type GetAnnouncementRequest struct { Id int64 `form:"id" validate:"required"` } -type GetAppcationResponse struct { - Config ApplicationConfig `json:"config"` - Applications []ApplicationResponseInfo `json:"applications"` -} - type GetAuthMethodConfigRequest struct { Method string `form:"method"` } @@ -766,7 +767,7 @@ type GetAvailablePaymentMethodsResponse struct { type GetBatchSendEmailTaskListRequest struct { Page int `form:"page"` Size int `form:"size"` - Scope string `form:"scope,omitempty"` + Scope *int8 `form:"scope,omitempty"` Status *uint8 `form:"status,omitempty"` } @@ -841,14 +842,10 @@ type GetLoginLogResponse struct { } type GetMessageLogListRequest struct { - Page int `form:"page"` - Size int `form:"size"` - Type string `form:"type"` - Platform string `form:"platform,omitempty"` - To string `form:"to,omitempty"` - Subject string `form:"subject,omitempty"` - Content string `form:"content,omitempty"` - Status int `form:"status,omitempty"` + Page int `form:"page"` + Size int `form:"size"` + Type uint8 `form:"type"` + Search string `form:"search,optional"` } type GetMessageLogListResponse struct { @@ -856,36 +853,10 @@ type GetMessageLogListResponse struct { List []MessageLog `json:"list"` } -type GetNodeDetailRequest struct { - Id int64 `form:"id" validate:"required"` -} - -type GetNodeGroupListResponse struct { - Total int64 `json:"total"` - List []ServerGroup `json:"list"` -} - type GetNodeMultiplierResponse struct { Periods []TimePeriod `json:"periods"` } -type GetNodeServerListRequest struct { - Page int `form:"page" validate:"required"` - Size int `form:"size" validate:"required"` - Tags string `form:"tags,omitempty"` - GroupId int64 `form:"group_id,omitempty"` - Search string `form:"search,omitempty"` -} - -type GetNodeServerListResponse struct { - Total int64 `json:"total"` - List []Server `json:"list"` -} - -type GetNodeTagListResponse struct { - Tags []string `json:"tags"` -} - type GetOAuthMethodsResponse struct { Methods []UserAuthMethod `json:"methods"` } @@ -918,20 +889,15 @@ type GetPaymentMethodListResponse struct { } type GetPreSendEmailCountRequest struct { - Scope string `json:"scope"` - RegisterStartTime int64 `json:"register_start_time,omitempty"` - RegisterEndTime int64 `json:"register_end_time,omitempty"` + Scope int8 `json:"scope"` + RegisterStartTime int64 `json:"register_start_time,omitempty"` + RegisterEndTime int64 `json:"register_end_time,omitempty"` } type GetPreSendEmailCountResponse struct { Count int64 `json:"count"` } -type GetRuleGroupResponse struct { - Total int64 `json:"total"` - List []ServerRuleGroup `json:"list"` -} - type GetServerConfigRequest struct { ServerCommon } @@ -942,6 +908,14 @@ type GetServerConfigResponse struct { Config interface{} `json:"config"` } +type GetServerProtocolsRequest struct { + Id int64 `form:"id"` +} + +type GetServerProtocolsResponse struct { + Protocols []Protocol `json:"protocols"` +} + type GetServerUserListRequest struct { ServerCommon } @@ -982,10 +956,10 @@ type GetSubscribeGroupListResponse struct { } type GetSubscribeListRequest struct { - Page int64 `form:"page" validate:"required"` - Size int64 `form:"size" validate:"required"` - GroupId int64 `form:"group_id,omitempty"` - Search string `form:"search,omitempty"` + Page int64 `form:"page" validate:"required"` + Size int64 `form:"size" validate:"required"` + Language string `form:"language,omitempty"` + Search string `form:"search,omitempty"` } type GetSubscribeListResponse struct { @@ -1003,6 +977,10 @@ type GetSubscribeLogResponse struct { Total int64 `json:"total"` } +type GetSubscriptionRequest struct { + Language string `form:"language"` +} + type GetSubscriptionResponse struct { List []Subscribe `json:"list"` } @@ -1061,11 +1039,6 @@ type GetUserLoginLogsResponse struct { Total int64 `json:"total"` } -type GetUserOnlineTimeStatisticsResponse struct { - WeeklyStats []WeeklyStat `json:"weekly_stats"` - ConnectionRecords ConnectionRecords `json:"connection_records"` -} - type GetUserSubscribeByIdRequest struct { Id int64 `form:"id" validate:"required"` } @@ -1105,6 +1078,17 @@ type GetUserSubscribeLogsResponse struct { Total int64 `json:"total"` } +type GetUserSubscribeResetTrafficLogsRequest struct { + Page int `form:"page"` + Size int `form:"size"` + UserSubscribeId int64 `form:"user_subscribe_id"` +} + +type GetUserSubscribeResetTrafficLogsResponse struct { + List []ResetSubscribeTrafficLog `json:"list"` + Total int64 `json:"total"` +} + type GetUserSubscribeTrafficLogsRequest struct { Page int `form:"page"` Size int `form:"size"` @@ -1135,11 +1119,26 @@ type GetUserTicketListResponse struct { List []Ticket `json:"list"` } +type GiftLog struct { + Type uint16 `json:"type"` + UserId int64 `json:"user_id"` + OrderNo string `json:"order_no"` + SubscribeId int64 `json:"subscribe_id"` + Amount int64 `json:"amount"` + Balance int64 `json:"balance"` + Remark string `json:"remark,omitempty"` + Timestamp int64 `json:"timestamp"` +} + type GoogleLoginCallbackRequest struct { Code string `form:"code"` State string `form:"state"` } +type HasMigrateSeverNodeResponse struct { + HasMigrate bool `json:"has_migrate"` +} + type Hysteria2 struct { Port int `json:"port" validate:"required"` HopPorts string `json:"hop_ports" validate:"required"` @@ -1162,20 +1161,39 @@ type LogResponse struct { List interface{} `json:"list"` } +type LogSetting struct { + AutoClear *bool `json:"auto_clear"` + ClearDays int64 `json:"clear_days"` +} + +type LoginLog struct { + UserId int64 `json:"user_id"` + Method string `json:"method"` + LoginIP string `json:"login_ip"` + UserAgent string `json:"user_agent"` + Success bool `json:"success"` + Timestamp int64 `json:"timestamp"` +} + type LoginResponse struct { Token string `json:"token"` } type MessageLog struct { - Id int64 `json:"id"` - Type string `json:"type"` - Platform string `json:"platform"` - To string `json:"to"` - Subject string `json:"subject"` - Content string `json:"content"` - Status int `json:"status"` - CreatedAt int64 `json:"created_at"` - UpdatedAt int64 `json:"updated_at"` + Id int64 `json:"id"` + Type uint8 `json:"type"` + Platform string `json:"platform"` + To string `json:"to"` + Subject string `json:"subject"` + Content interface{} `json:"content"` + Status uint8 `json:"status"` + CreatedAt int64 `json:"created_at"` +} + +type MigrateServerNodeResponse struct { + Succee uint64 `json:"succee"` + Fail uint64 `json:"fail"` + Message string `json:"message,omitempty"` } type MobileAuthenticateConfig struct { @@ -1184,6 +1202,20 @@ type MobileAuthenticateConfig struct { Whitelist []string `json:"whitelist"` } +type Node struct { + Id int64 `json:"id"` + Name string `json:"name"` + Tags []string `json:"tags"` + Port uint16 `json:"port"` + Address string `json:"address"` + ServerId int64 `json:"server_id"` + Protocol string `json:"protocol"` + Enabled *bool `json:"enabled"` + Sort int `json:"sort,omitempty"` + CreatedAt int64 `json:"created_at"` + UpdatedAt int64 `json:"updated_at"` +} + type NodeConfig struct { NodeSecret string `json:"node_secret"` NodePullInterval int64 `json:"node_pull_interval"` @@ -1196,18 +1228,6 @@ type NodeRelay struct { Prefix string `json:"prefix"` } -type NodeSortRequest struct { - Sort []SortItem `json:"sort"` -} - -type NodeStatus struct { - Online interface{} `json:"online"` - Cpu float64 `json:"cpu"` - Mem float64 `json:"mem"` - Disk float64 `json:"disk"` - UpdatedAt int64 `json:"updated_at"` -} - type OAthLoginRequest struct { Method string `json:"method" validate:"required"` // google, facebook, apple, telegram, github etc. Redirect string `json:"redirect"` @@ -1402,6 +1422,40 @@ type PrivacyPolicyConfig struct { PrivacyPolicy string `json:"privacy_policy"` } +type Protocol struct { + Type string `json:"type"` + Port uint16 `json:"port"` + Security string `json:"security,omitempty"` + SNI string `json:"sni,omitempty"` + AllowInsecure bool `json:"allow_insecure,omitempty"` + Fingerprint string `json:"fingerprint,omitempty"` + RealityServerAddr string `json:"reality_server_addr,omitempty"` + RealityServerPort int `json:"reality_server_port,omitempty"` + RealityPrivateKey string `json:"reality_private_key,omitempty"` + RealityPublicKey string `json:"reality_public_key,omitempty"` + RealityShortId string `json:"reality_short_id,omitempty"` + Transport string `json:"transport,omitempty"` + Host string `json:"host,omitempty"` + Path string `json:"path,omitempty"` + ServiceName string `json:"service_name,omitempty"` + Cipher string `json:"cipher,omitempty"` + ServerKey string `json:"server_key,omitempty"` + Flow string `json:"flow,omitempty"` + HopPorts string `json:"hop_ports,omitempty"` + HopInterval int `json:"hop_interval,omitempty"` + ObfsPassword string `json:"obfs_password,omitempty"` + DisableSNI bool `json:"disable_sni,omitempty"` + ReduceRtt bool `json:"reduce_rtt,omitempty"` + UDPRelayMode string `json:"udp_relay_mode,omitempty"` + CongestionController string `json:"congestion_controller,omitempty"` + Plugin string `json:"plugin,omitempty"` // obfs, v2ray-plugin, simple-obfs + PluginOptions string `json:"plugin_options,omitempty"` // plugin options, eg: obfs=http;obfs-host=www.bing.com + Multiplex string `json:"multiplex,omitempty"` // mux, eg: off/low/medium/high + PaddingScheme string `json:"padding_scheme,omitempty"` // padding scheme + UpMbps int `json:"up_mbps,omitempty"` // upload speed limit + DownMbps int `json:"down_mbps,omitempty"` // download speed limit +} + type PubilcRegisterConfig struct { StopRegister bool `json:"stop_register"` EnableIpRegisterLimit bool `json:"enable_ip_register_limit"` @@ -1445,6 +1499,10 @@ type QueryDocumentListResponse struct { List []Document `json:"list"` } +type QueryNodeTagResponse struct { + Tags []string `json:"tags"` +} + type QueryOrderDetailRequest struct { OrderNo string `form:"order_no" validate:"required"` } @@ -1481,11 +1539,57 @@ type QueryPurchaseOrderResponse struct { Token string `json:"token,omitempty"` } +type QueryQuotaTaskListRequest struct { + Page int `form:"page"` + Size int `form:"size"` + Status *uint8 `form:"status,omitempty"` +} + +type QueryQuotaTaskListResponse struct { + Total int64 `json:"total"` + List []QuotaTask `json:"list"` +} + +type QueryQuotaTaskPreCountRequest struct { + Subscribers []int64 `json:"subscribers"` + IsActive *bool `json:"is_active"` + StartTime int64 `json:"start_time"` + EndTime int64 `json:"end_time"` +} + +type QueryQuotaTaskPreCountResponse struct { + Count int64 `json:"count"` +} + +type QueryQuotaTaskStatusRequest struct { + Id int64 `json:"id"` +} + +type QueryQuotaTaskStatusResponse struct { + Status uint8 `json:"status"` + Current int64 `json:"current"` + Total int64 `json:"total"` + Errors string `json:"errors"` +} + +type QueryServerConfigRequest struct { + ServerID int64 `path:"server_id"` + SecretKey string `header:"secret_key"` +} + +type QueryServerConfigResponse struct { + Protocols []Protocol `json:"protocols"` +} + type QuerySubscribeGroupListResponse struct { List []SubscribeGroup `json:"list"` Total int64 `json:"total"` } +type QuerySubscribeListRequest struct { + Language string `form:"language"` +} + type QuerySubscribeListResponse struct { List []Subscribe `json:"list"` Total int64 `json:"total"` @@ -1507,8 +1611,8 @@ type QueryUserAffiliateListResponse struct { } type QueryUserBalanceLogListResponse struct { - List []UserBalanceLog `json:"list"` - Total int64 `json:"total"` + List []BalanceLog `json:"list"` + Total int64 `json:"total"` } type QueryUserCommissionLogListRequest struct { @@ -1526,8 +1630,23 @@ type QueryUserSubscribeListResponse struct { Total int64 `json:"total"` } -type QueryUserSubscribeResp struct { - Data []UserSubscribeData `json:"data"` +type QuotaTask struct { + Id int64 `json:"id"` + Subscribers []int64 `json:"subscribers"` + IsActive *bool `json:"is_active"` + StartTime int64 `json:"start_time"` + EndTime int64 `json:"end_time"` + ResetTraffic bool `json:"reset_traffic"` + Days uint64 `json:"days"` + GiftType uint8 `json:"gift_type"` + GiftValue uint64 `json:"gift_value"` + Objects []int64 `json:"objects"` // UserSubscribe IDs + Status uint8 `json:"status"` + Total int64 `json:"total"` + Current int64 `json:"current"` + Errors string `json:"errors"` + CreatedAt int64 `json:"created_at"` + UpdatedAt int64 `json:"updated_at"` } type RechargeOrderRequest struct { @@ -1550,6 +1669,15 @@ type RegisterConfig struct { IpRegisterLimitDuration int64 `json:"ip_register_limit_duration"` } +type RegisterLog struct { + UserId int64 `json:"user_id"` + AuthMethod string `json:"auth_method"` + Identifier string `json:"identifier"` + RegisterIP string `json:"register_ip"` + UserAgent string `json:"user_agent"` + Timestamp int64 `json:"timestamp"` +} + type RenewalOrderRequest struct { UserSubscribeID int64 `json:"user_subscribe_id"` Quantity int64 `json:"quantity"` @@ -1570,6 +1698,26 @@ type ResetPasswordRequest struct { CfToken string `json:"cf_token,optional"` } +type ResetSortRequest struct { + Sort []SortItem `json:"sort"` +} + +type ResetSubscribeLog struct { + Type uint16 `json:"type"` + UserId int64 `json:"user_id"` + UserSubscribeId int64 `json:"user_subscribe_id"` + OrderNo string `json:"order_no,omitempty"` + Timestamp int64 `json:"timestamp"` +} + +type ResetSubscribeTrafficLog struct { + Id int64 `json:"id"` + Type uint16 `json:"type"` + UserSubscribeId int64 `json:"user_subscribe_id"` + OrderNo string `json:"order_no,omitempty"` + Timestamp int64 `json:"timestamp"` +} + type ResetTrafficOrderRequest struct { UserSubscribeID int64 `json:"user_subscribe_id"` Payment int64 `json:"payment"` @@ -1617,24 +1765,18 @@ type SendSmsCodeRequest struct { } type Server struct { - Id int64 `json:"id"` - Tags []string `json:"tags"` - Country string `json:"country"` - City string `json:"city"` - Name string `json:"name"` - ServerAddr string `json:"server_addr"` - RelayMode string `json:"relay_mode"` - RelayNode []NodeRelay `json:"relay_node"` - SpeedLimit int `json:"speed_limit"` - TrafficRatio float32 `json:"traffic_ratio"` - GroupId int64 `json:"group_id"` - Protocol string `json:"protocol"` - Config interface{} `json:"config"` - Enable *bool `json:"enable"` - CreatedAt int64 `json:"created_at"` - UpdatedAt int64 `json:"updated_at"` - Status *NodeStatus `json:"status"` - Sort int64 `json:"sort"` + Id int64 `json:"id"` + Name string `json:"name"` + Country string `json:"country"` + City string `json:"city"` + Ratio float32 `json:"ratio"` + Address string `json:"address"` + Sort int `json:"sort"` + Protocols []Protocol `json:"protocols"` + LastReportedAt int64 `json:"last_reported_at"` + Status ServerStatus `json:"status"` + CreatedAt int64 `json:"created_at"` + UpdatedAt int64 `json:"updated_at"` } type ServerBasic struct { @@ -1656,6 +1798,20 @@ type ServerGroup struct { UpdatedAt int64 `json:"updated_at"` } +type ServerOnlineIP struct { + IP string `json:"ip"` + Protocol string `json:"protocol"` +} + +type ServerOnlineUser struct { + IP []ServerOnlineIP `json:"ip"` + UserId int64 `json:"user_id"` + Subscribe string `json:"subscribe"` + SubscribeId int64 `json:"subscribe_id"` + Traffic int64 `json:"traffic"` + ExpiredAt int64 `json:"expired_at"` +} + type ServerPushStatusRequest struct { ServerCommon Cpu float64 `json:"cpu"` @@ -1682,8 +1838,17 @@ type ServerRuleGroup struct { UpdatedAt int64 `json:"updated_at"` } +type ServerStatus struct { + Cpu float64 `json:"cpu"` + Mem float64 `json:"mem"` + Disk float64 `json:"disk"` + Protocol string `json:"protocol"` + Online []ServerOnlineUser `json:"online"` + Status string `json:"status"` +} + type ServerTotalDataResponse struct { - OnlineUserIPs int64 `json:"online_user_ips"` + OnlineUsers int64 `json:"online_users"` OnlineServers int64 `json:"online_servers"` OfflineServers int64 `json:"offline_servers"` TodayUpload int64 `json:"today_upload"` @@ -1704,6 +1869,15 @@ type ServerTrafficData struct { Download int64 `json:"download"` } +type ServerTrafficLog struct { + ServerId int64 `json:"server_id"` // Server ID + Upload int64 `json:"upload"` // Upload traffic in bytes + Download int64 `json:"download"` // Download traffic in bytes + Total int64 `json:"total"` // Total traffic in bytes (Upload + Download) + Date string `json:"date"` // Date in YYYY-MM-DD format + Details bool `json:"details"` // Whether to show detailed traffic +} + type ServerUser struct { Id int64 `json:"id"` UUID string `json:"uuid"` @@ -1760,6 +1934,7 @@ type StripePayment struct { type Subscribe struct { Id int64 `json:"id"` Name string `json:"name"` + Language string `json:"language"` Description string `json:"description"` UnitPrice int64 `json:"unit_price"` UnitTime string `json:"unit_time"` @@ -1770,9 +1945,8 @@ type Subscribe struct { SpeedLimit int64 `json:"speed_limit"` DeviceLimit int64 `json:"device_limit"` Quota int64 `json:"quota"` - GroupId int64 `json:"group_id"` - ServerGroup []int64 `json:"server_group"` - Server []int64 `json:"server"` + Nodes []int64 `json:"nodes"` + NodeTags []string `json:"node_tags"` Show bool `json:"show"` Sell bool `json:"sell"` Sort int64 `json:"sort"` @@ -1836,6 +2010,15 @@ type SubscribeItem struct { Sold int64 `json:"sold"` } +type SubscribeLog struct { + UserId int64 `json:"user_id"` + Token string `json:"token"` + UserAgent string `json:"user_agent"` + ClientIP string `json:"client_ip"` + UserSubscribeId int64 `json:"user_subscribe_id"` + Timestamp int64 `json:"timestamp"` +} + type SubscribeSortRequest struct { Sort []SortItem `json:"sort"` } @@ -1866,6 +2049,7 @@ type TelephoneLoginRequest struct { TelephoneAreaCode string `json:"telephone_area_code" validate:"required"` Password string `json:"password"` IP string `header:"X-Original-Forwarded-For"` + UserAgent string `header:"User-Agent"` CfToken string `json:"cf_token,optional"` } @@ -1876,6 +2060,7 @@ type TelephoneRegisterRequest struct { Invite string `json:"invite,optional"` Code string `json:"code,optional"` IP string `header:"X-Original-Forwarded-For"` + UserAgent string `header:"User-Agent"` CfToken string `json:"cf_token,optional"` } @@ -1885,6 +2070,7 @@ type TelephoneResetPasswordRequest struct { Password string `json:"password" validate:"required"` Code string `json:"code,optional"` IP string `header:"X-Original-Forwarded-For"` + UserAgent string `header:"User-Agent"` CfToken string `json:"cf_token,optional"` } @@ -1918,6 +2104,11 @@ type TimePeriod struct { Multiplier float32 `json:"multiplier"` } +type ToggleNodeStatusRequest struct { + Id int64 `json:"id"` + Enable *bool `json:"enable"` +} + type TosConfig struct { TosContent string `json:"tos_content"` } @@ -1932,6 +2123,16 @@ type TrafficLog struct { Timestamp int64 `json:"timestamp"` } +type TrafficLogDetails struct { + Id int64 `json:"id"` + ServerId int64 `json:"server_id"` + UserId int64 `json:"user_id"` + SubscribeId int64 `json:"subscribe_id"` + Download int64 `json:"download"` + Upload int64 `json:"upload"` + Timestamp int64 `json:"timestamp"` +} + type TransportConfig struct { Path string `json:"path"` Host string `json:"host"` @@ -1998,25 +2199,6 @@ type UpdateAnnouncementRequest struct { Popup *bool `json:"popup"` } -type UpdateApplicationRequest struct { - Id int64 `json:"id" validate:"required"` - Icon string `json:"icon"` - Name string `json:"name"` - Description string `json:"description"` - SubscribeType string `json:"subscribe_type"` - Platform ApplicationPlatform `json:"platform"` -} - -type UpdateApplicationVersionRequest struct { - Id int64 `json:"id" validate:"required"` - Url string `json:"url"` - Version string `json:"version" validate:"required"` - Description string `json:"description"` - Platform string `json:"platform" validate:"required,oneof=windows mac linux android ios harmony"` - IsDefault bool `json:"is_default"` - ApplicationId int64 `json:"application_id" validate:"required"` -} - type UpdateAuthMethodConfigRequest struct { Id int64 `json:"id"` Method string `json:"method"` @@ -2057,28 +2239,15 @@ type UpdateDocumentRequest struct { Show *bool `json:"show"` } -type UpdateNodeGroupRequest struct { - Id int64 `json:"id" validate:"required"` - Name string `json:"name" validate:"required"` - Description string `json:"description"` -} - type UpdateNodeRequest struct { - Id int64 `json:"id" validate:"required"` - Tags []string `json:"tags"` - Country string `json:"country"` - City string `json:"city"` - Name string `json:"name" validate:"required"` - ServerAddr string `json:"server_addr" validate:"required"` - RelayMode string `json:"relay_mode"` - RelayNode []NodeRelay `json:"relay_node"` - SpeedLimit int `json:"speed_limit"` - TrafficRatio float32 `json:"traffic_ratio"` - GroupId int64 `json:"group_id"` - Protocol string `json:"protocol" validate:"required"` - Config interface{} `json:"config" validate:"required"` - Enable *bool `json:"enable"` - Sort int64 `json:"sort"` + Id int64 `json:"id"` + Name string `json:"name"` + Tags []string `json:"tags,omitempty"` + Port uint16 `json:"port"` + Address string `json:"address"` + ServerId int64 `json:"server_id"` + Protocol string `json:"protocol"` + Enabled *bool `json:"enabled"` } type UpdateOrderStatusRequest struct { @@ -2088,11 +2257,6 @@ type UpdateOrderStatusRequest struct { TradeNo string `json:"trade_no,omitempty"` } -type UpdatePasswordRequeset struct { - Password string `json:"password"` - NewPassword string `json:"new_password"` -} - type UpdatePaymentMethodRequest struct { Id int64 `json:"id" validate:"required"` Name string `json:"name" validate:"required"` @@ -2107,15 +2271,15 @@ type UpdatePaymentMethodRequest struct { Enable *bool `json:"enable" validate:"required"` } -type UpdateRuleGroupRequest struct { - Id int64 `json:"id" validate:"required"` - Icon string `json:"icon"` - Type string `json:"type"` - Name string `json:"name" validate:"required"` - Tags []string `json:"tags"` - Rules string `json:"rules"` - Default bool `json:"default"` - Enable bool `json:"enable"` +type UpdateServerRequest struct { + Id int64 `json:"id"` + Name string `json:"name"` + Country string `json:"country,omitempty"` + City string `json:"city,omitempty"` + Ratio float32 `json:"ratio"` + Address string `json:"address"` + Sort int `json:"sort,omitempty"` + Protocols []Protocol `json:"protocols"` } type UpdateSubscribeApplicationRequest struct { @@ -2140,6 +2304,7 @@ type UpdateSubscribeGroupRequest struct { type UpdateSubscribeRequest struct { Id int64 `json:"id" validate:"required"` Name string `json:"name" validate:"required"` + Language string `json:"language"` Description string `json:"description"` UnitPrice int64 `json:"unit_price"` UnitTime string `json:"unit_time"` @@ -2150,9 +2315,8 @@ type UpdateSubscribeRequest struct { SpeedLimit int64 `json:"speed_limit"` DeviceLimit int64 `json:"device_limit"` Quota int64 `json:"quota"` - GroupId int64 `json:"group_id"` - ServerGroup []int64 `json:"server_group"` - Server []int64 `json:"server"` + Nodes []int64 `json:"nodes"` + NodeTags []string `json:"node_tags"` Show *bool `json:"show"` Sell *bool `json:"sell"` Sort int64 `json:"sort"` @@ -2174,17 +2338,19 @@ type UpdateUserAuthMethodRequest struct { } type UpdateUserBasiceInfoRequest struct { - UserId int64 `json:"user_id" validate:"required"` - Password string `json:"password"` - Avatar string `json:"avatar"` - Balance int64 `json:"balance"` - Commission int64 `json:"commission"` - GiftAmount int64 `json:"gift_amount"` - Telegram int64 `json:"telegram"` - ReferCode string `json:"refer_code"` - RefererId int64 `json:"referer_id"` - Enable bool `json:"enable"` - IsAdmin bool `json:"is_admin"` + UserId int64 `json:"user_id" validate:"required"` + Password string `json:"password"` + Avatar string `json:"avatar"` + Balance int64 `json:"balance"` + Commission int64 `json:"commission"` + ReferralPercentage uint8 `json:"referral_percentage"` + OnlyFirstPurchase bool `json:"only_first_purchase"` + GiftAmount int64 `json:"gift_amount"` + Telegram int64 `json:"telegram"` + ReferCode string `json:"refer_code"` + RefererId int64 `json:"referer_id"` + Enable bool `json:"enable"` + IsAdmin bool `json:"is_admin"` } type UpdateUserNotifyRequest struct { @@ -2225,6 +2391,8 @@ type User struct { Avatar string `json:"avatar"` Balance int64 `json:"balance"` Commission int64 `json:"commission"` + ReferralPercentage uint8 `json:"referral_percentage"` + OnlyFirstPurchase bool `json:"only_first_purchase"` GiftAmount int64 `json:"gift_amount"` Telegram int64 `json:"telegram"` ReferCode string `json:"refer_code"` @@ -2256,16 +2424,6 @@ type UserAuthMethod struct { Verified bool `json:"verified"` } -type UserBalanceLog struct { - Id int64 `json:"id"` - UserId int64 `json:"user_id"` - Amount int64 `json:"amount"` - Type uint8 `json:"type"` - OrderId int64 `json:"order_id"` - Balance int64 `json:"balance"` - CreatedAt int64 `json:"created_at"` -} - type UserDevice struct { Id int64 `json:"id"` Ip string `json:"ip"` @@ -2277,26 +2435,13 @@ type UserDevice struct { UpdatedAt int64 `json:"updated_at"` } -type UserInfoResponse struct { - Id int64 `json:"id"` - Balance int64 `json:"balance"` - Email string `json:"email"` - RefererId int64 `json:"referer_id"` - ReferCode string `json:"refer_code"` - Avatar string `json:"avatar"` - AreaCode string `json:"area_code"` - Telephone string `json:"telephone"` - Devices []UserDevice `json:"devices"` - AuthMethods []UserAuthMethod `json:"auth_methods"` -} - type UserLoginLog struct { Id int64 `json:"id"` UserId int64 `json:"user_id"` LoginIP string `json:"login_ip"` UserAgent string `json:"user_agent"` Success bool `json:"success"` - CreatedAt int64 `json:"created_at"` + Timestamp int64 `json:"timestamp"` } type UserLoginRequest struct { @@ -2350,11 +2495,6 @@ type UserSubscribe struct { UpdatedAt int64 `json:"updated_at"` } -type UserSubscribeData struct { - SubscribeId int64 `json:"subscribe_id"` - UserSubscribeId int64 `json:"user_subscribe_id"` -} - type UserSubscribeDetail struct { Id int64 `json:"id"` UserId int64 `json:"user_id"` @@ -2381,15 +2521,17 @@ type UserSubscribeLog struct { Token string `json:"token"` IP string `json:"ip"` UserAgent string `json:"user_agent"` - CreatedAt int64 `json:"created_at"` + Timestamp int64 `json:"timestamp"` } -type UserSubscribeResetPeriodRequest struct { - UserSubscribeId int64 `json:"user_subscribe_id"` -} - -type UserSubscribeResetPeriodResponse struct { - Status bool `json:"status"` +type UserSubscribeTrafficLog struct { + SubscribeId int64 `json:"subscribe_id"` // Subscribe ID + UserId int64 `json:"user_id"` // User ID + Upload int64 `json:"upload"` // Upload traffic in bytes + Download int64 `json:"download"` // Download traffic in bytes + Total int64 `json:"total"` // Total traffic in bytes (Upload + Download) + Date string `json:"date"` // Date in YYYY-MM-DD format + Details bool `json:"details"` // Whether to show detailed traffic } type UserTraffic struct { @@ -2469,9 +2611,3 @@ type VmessProtocol struct { Network string `json:"network"` Transport string `json:"transport"` } - -type WeeklyStat struct { - Day int `json:"day"` - DayName string `json:"day_name"` - Hours float64 `json:"hours"` -} diff --git a/pkg/constant/types.go b/pkg/constant/types.go index ea34b57..a2db39b 100644 --- a/pkg/constant/types.go +++ b/pkg/constant/types.go @@ -1,8 +1,6 @@ package constant -import ( - "encoding/json" -) +import "encoding/json" // Used for type cloning conversion const ( @@ -46,7 +44,17 @@ type TemporaryOrderInfo struct { InviteCode string `json:"invite_code,omitempty"` } -func (t TemporaryOrderInfo) Marshal() string { - value, _ := json.Marshal(t) - return string(value) +func (t *TemporaryOrderInfo) Unmarshal(data []byte) error { + type Alias TemporaryOrderInfo + aux := (*Alias)(t) + return json.Unmarshal(data, aux) +} + +func (t *TemporaryOrderInfo) Marshal() ([]byte, error) { + type Alias TemporaryOrderInfo + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(t), + }) } diff --git a/pkg/email/worker.go b/pkg/email/worker.go index 5ebe551..fd5aba4 100644 --- a/pkg/email/worker.go +++ b/pkg/email/worker.go @@ -3,11 +3,11 @@ package email import ( "context" "encoding/json" - "strings" "time" "github.com/perfect-panel/server/internal/model/task" "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/tool" "gorm.io/gorm" ) @@ -50,14 +50,13 @@ func (w *Worker) Start() { limit.Lock() defer limit.Unlock() tx := w.db.WithContext(w.ctx) - var taskInfo task.EmailTask - if err := tx.Model(&task.EmailTask{}).Where("id = ?", w.id).First(&taskInfo).Error; err != nil { + var taskInfo task.Task + if err := tx.Model(&task.Task{}).Where("id = ?", w.id).First(&taskInfo).Error; err != nil { logger.Error("Batch Send Email", logger.Field("message", "Failed to find task"), logger.Field("error", err.Error()), logger.Field("task_id", w.id), ) - w.status = 2 // 设置状态为已完成 return } if taskInfo.Status != 0 { @@ -65,27 +64,50 @@ func (w *Worker) Start() { logger.Field("message", "Task already completed or in progress"), logger.Field("task_id", w.id), ) - w.status = 2 // 设置状态为已完成 return } - if taskInfo.Recipients == "" && taskInfo.Additional == "" { + + var scope task.EmailScope + if err := json.Unmarshal([]byte(taskInfo.Scope), &scope); err != nil { + logger.Error("Batch Send Email", + logger.Field("message", "Failed to parse task scope"), + logger.Field("error", err.Error()), + logger.Field("task_id", w.id), + ) + return + } + + if len(scope.Recipients) == 0 && len(scope.Additional) == 0 { logger.Error("Batch Send Email", logger.Field("message", "No recipients or additional emails provided"), logger.Field("task_id", w.id), ) - w.status = 2 // 设置状态为已完成 return } + + var content task.EmailContent + if err := json.Unmarshal([]byte(taskInfo.Content), &content); err != nil { + logger.Error("Batch Send Email", + logger.Field("message", "Failed to parse task content"), + logger.Field("error", err.Error()), + logger.Field("task_id", w.id), + ) + return + } + w.status = 1 // 设置状态为运行中 var recipients []string // 解析收件人 - if taskInfo.Recipients != "" { - recipients = append(recipients, strings.Split(taskInfo.Recipients, "\n")...) + if len(scope.Recipients) > 0 { + recipients = append(recipients, scope.Recipients...) } // 解析附加收件人 - if taskInfo.Additional != "" { - recipients = append(recipients, strings.Split(taskInfo.Additional, "\n")...) + if len(scope.Additional) > 0 { + recipients = append(recipients, scope.Additional...) } + // 去重和清理空字符串 + recipients = tool.RemoveDuplicateElements(recipients...) + if len(recipients) == 0 { logger.Error("Batch Send Email", logger.Field("message", "No valid recipients found"), @@ -97,10 +119,10 @@ func (w *Worker) Start() { // 设置发送间隔时间 var intervalTime time.Duration - if taskInfo.Interval == 0 { + if scope.Interval == 0 { intervalTime = 1 * time.Second } else { - intervalTime = time.Duration(taskInfo.Interval) * time.Second + intervalTime = time.Duration(scope.Interval) * time.Second } var errors []ErrorInfo @@ -115,12 +137,11 @@ func (w *Worker) Start() { return default: } - if taskInfo.Status == 0 { taskInfo.Status = 1 // 1 表示任务进行中 } - if err := w.sender.Send([]string{recipient}, taskInfo.Subject, taskInfo.Content); err != nil { + if err := w.sender.Send([]string{recipient}, content.Subject, content.Content); err != nil { logger.Error("Batch Send Email", logger.Field("message", "Failed to send email"), logger.Field("error", err.Error()), @@ -136,19 +157,26 @@ func (w *Worker) Start() { taskInfo.Errors = string(text) } count++ - if err := tx.Model(&task.EmailTask{}).Save(&taskInfo).Error; err != nil { + taskInfo.Current = count + if err := tx.Model(&task.Task{}).Where("`id` = ?", taskInfo.Id).Save(&taskInfo).Error; err != nil { logger.Error("Batch Send Email", logger.Field("message", "Failed to update task progress"), logger.Field("error", err.Error()), logger.Field("task_id", w.id), ) + errors = append(errors, ErrorInfo{ + Error: err.Error(), + Email: recipient, + Time: time.Now().Unix(), + }) w.status = 2 // 设置状态为已完成 - return } time.Sleep(intervalTime) } - taskInfo.Status = 2 // 设置状态为已完成 - if err := tx.Model(&task.EmailTask{}).Save(&taskInfo).Error; err != nil { + taskInfo.Status = 2 // 2 表示任务已完成 + w.status = 2 // 设置状态为已完成 + + if err := tx.Model(&task.Task{}).Where("`id` = ?", taskInfo.Id).Save(&taskInfo).Error; err != nil { logger.Error("Batch Send Email", logger.Field("message", "Failed to finalize task"), logger.Field("error", err.Error()), diff --git a/pkg/orm/tool_test.go b/pkg/orm/tool_test.go index 95dcdd4..d415bbd 100644 --- a/pkg/orm/tool_test.go +++ b/pkg/orm/tool_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/perfect-panel/server/internal/model/task" + "gorm.io/driver/mysql" "gorm.io/gorm" ) @@ -30,7 +31,7 @@ func TestMysql(t *testing.T) { if err != nil { t.Fatalf("Failed to connect to MySQL: %v", err) } - err = db.Migrator().AutoMigrate(&task.EmailTask{}) + err = db.Migrator().AutoMigrate(&task.Task{}) if err != nil { t.Fatalf("Failed to auto migrate: %v", err) return diff --git a/pkg/payment/platform.go b/pkg/payment/platform.go index 2955391..42b8815 100644 --- a/pkg/payment/platform.go +++ b/pkg/payment/platform.go @@ -9,10 +9,12 @@ const ( AlipayF2F EPay Balance - UNSUPPORTED + CryptoSaaS + UNSUPPORTED Platform = -1 ) var platformNames = map[string]Platform{ + "CryptoSaaS": CryptoSaaS, "Stripe": Stripe, "AlipayF2F": AlipayF2F, "EPay": EPay, @@ -68,5 +70,14 @@ func GetSupportedPlatforms() []types.PlatformInfo { "key": "Key", }, }, + { + Platform: CryptoSaaS.String(), + PlatformUrl: "https://t.me/CryptoSaaSBot", + PlatformFieldDescription: map[string]string{ + "endpoint": "API Endpoint", + "account_id": "Account ID", + "secret_key": "Secret Key", + }, + }, } } diff --git a/pkg/tool/slice.go b/pkg/tool/slice.go index 9eef3fc..3797878 100644 --- a/pkg/tool/slice.go +++ b/pkg/tool/slice.go @@ -59,6 +59,7 @@ func Int64SliceToString(intSlice []int64) string { // string slice to string func StringSliceToString(stringSlice []string) string { + stringSlice = RemoveDuplicateElements(stringSlice...) return strings.Join(stringSlice, ",") } diff --git a/pkg/tool/time.go b/pkg/tool/time.go index 65008f5..31c6883 100644 --- a/pkg/tool/time.go +++ b/pkg/tool/time.go @@ -144,3 +144,10 @@ func DayDiff(startTime, endTime time.Time) int64 { duration := endTime.Sub(startTime) return int64(duration.Hours() / 24) // 转换为整天数 } + +// HourDiff 计算两个时间点之间的小时差 +func HourDiff(startTime, endTime time.Time) int64 { + // 计算时间差 + duration := endTime.Sub(startTime) + return int64(duration.Hours()) // 返回小时数,可能包含小数部分 +} diff --git a/ppanel.api b/ppanel.api index a3be7dd..10c83c2 100644 --- a/ppanel.api +++ b/ppanel.api @@ -37,14 +37,5 @@ import ( "apis/public/payment.api" "apis/public/document.api" "apis/public/portal.api" - "apis/app/auth.api" - "apis/app/user.api" - "apis/app/node.api" - "apis/app/ws.api" - "apis/app/order.api" - "apis/app/announcement.api" - "apis/app/payment.api" - "apis/app/document.api" - "apis/app/subscribe.api" ) diff --git a/queue/handler/routes.go b/queue/handler/routes.go index 15bc8f1..edf2293 100644 --- a/queue/handler/routes.go +++ b/queue/handler/routes.go @@ -7,6 +7,7 @@ import ( orderLogic "github.com/perfect-panel/server/queue/logic/order" smslogic "github.com/perfect-panel/server/queue/logic/sms" "github.com/perfect-panel/server/queue/logic/subscription" + "github.com/perfect-panel/server/queue/logic/task" "github.com/perfect-panel/server/queue/logic/traffic" "github.com/perfect-panel/server/queue/types" @@ -39,4 +40,10 @@ func RegisterHandlers(mux *asynq.ServeMux, serverCtx *svc.ServiceContext) { // ScheduledBatchSendEmail mux.Handle(types.ScheduledBatchSendEmail, emailLogic.NewBatchEmailLogic(serverCtx)) + + // ScheduledTrafficStat + mux.Handle(types.SchedulerTrafficStat, traffic.NewStatLogic(serverCtx)) + + // ForthwithQuotaTask + mux.Handle(types.ForthwithQuotaTask, task.NewQuotaTaskLogic(serverCtx)) } diff --git a/queue/logic/country/getCountryLogic.go b/queue/logic/country/getCountryLogic.go index 2b7ac41..75e0f6f 100644 --- a/queue/logic/country/getCountryLogic.go +++ b/queue/logic/country/getCountryLogic.go @@ -2,14 +2,9 @@ package countrylogic import ( "context" - "encoding/json" - - "github.com/perfect-panel/server/pkg/logger" "github.com/hibiken/asynq" "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/ip" - "github.com/perfect-panel/server/queue/types" ) type GetNodeCountryLogic struct { @@ -22,39 +17,6 @@ func NewGetNodeCountryLogic(svcCtx *svc.ServiceContext) *GetNodeCountryLogic { } } func (l *GetNodeCountryLogic) ProcessTask(ctx context.Context, task *asynq.Task) error { - var payload types.GetNodeCountry - if err := json.Unmarshal(task.Payload(), &payload); err != nil { - logger.WithContext(ctx).Error("[GetNodeCountryLogic] Unmarshal payload failed", - logger.Field("error", err.Error()), - logger.Field("payload", task.Payload()), - ) - return nil - } - serverAddr := payload.ServerAddr - resp, err := ip.GetRegionByIp(serverAddr) - if err != nil { - logger.WithContext(ctx).Error("[GetNodeCountryLogic] ", logger.Field("error", err.Error()), logger.Field("serverAddr", serverAddr)) - return nil - } - servers, err := l.svcCtx.ServerModel.FindNodeByServerAddrAndProtocol(ctx, payload.ServerAddr, payload.Protocol) - if err != nil { - logger.WithContext(ctx).Error("[GetNodeCountryLogic] FindNodeByServerAddrAnd", logger.Field("error", err.Error()), logger.Field("serverAddr", serverAddr)) - return err - } - if len(servers) == 0 { - return nil - } - for _, ser := range servers { - ser.Country = resp.Country - ser.City = resp.City - ser.Latitude = resp.Latitude - ser.Longitude = resp.Longitude - err := l.svcCtx.ServerModel.Update(ctx, ser) - if err != nil { - logger.WithContext(ctx).Error("[GetNodeCountryLogic] ", logger.Field("error", err.Error()), logger.Field("id", ser.Id)) - } - } - logger.WithContext(ctx).Info("[GetNodeCountryLogic] ", logger.Field("country", resp.Country), logger.Field("city", resp.Country)) return nil } diff --git a/queue/logic/email/batchEmailLogic.go b/queue/logic/email/batchEmailLogic.go index d9f9505..2aa8123 100644 --- a/queue/logic/email/batchEmailLogic.go +++ b/queue/logic/email/batchEmailLogic.go @@ -44,8 +44,8 @@ func (l *BatchEmailLogic) ProcessTask(ctx context.Context, task *asynq.Task) err return asynq.SkipRetry } tx := l.svcCtx.DB.WithContext(ctx) - var taskInfo taskModel.EmailTask - if err = tx.Model(&taskModel.EmailTask{}).Where("id = ?", taskID).First(&taskInfo).Error; err != nil { + var taskInfo taskModel.Task + if err = tx.Model(&taskModel.Task{}).Where("id = ?", taskID).First(&taskInfo).Error; err != nil { logger.WithContext(ctx).Error("[BatchEmailLogic] ProcessTask failed", logger.Field("error", err.Error()), logger.Field("taskID", taskID), diff --git a/queue/logic/email/sendEmailLogic.go b/queue/logic/email/sendEmailLogic.go index 26ee1c0..7a56350 100644 --- a/queue/logic/email/sendEmailLogic.go +++ b/queue/logic/email/sendEmailLogic.go @@ -1,8 +1,11 @@ package emailLogic import ( + "bytes" "context" "encoding/json" + "text/template" + "time" "github.com/perfect-panel/server/pkg/logger" @@ -31,8 +34,7 @@ func (l *SendEmailLogic) ProcessTask(ctx context.Context, task *asynq.Task) erro ) return nil } - messageLog := log.MessageLog{ - Type: log.Email.String(), + messageLog := log.Message{ Platform: l.svcCtx.Config.Email.Platform, To: payload.Email, Subject: payload.Subject, @@ -43,18 +45,111 @@ func (l *SendEmailLogic) ProcessTask(ctx context.Context, task *asynq.Task) erro logger.WithContext(ctx).Error("[SendEmailLogic] NewSender failed", logger.Field("error", err.Error())) return nil } - err = sender.Send([]string{payload.Email}, payload.Subject, payload.Content) + var content string + switch payload.Type { + case types.EmailTypeVerify: + tpl, _ := template.New("verify").Parse(l.svcCtx.Config.Email.VerifyEmailTemplate) + var result bytes.Buffer + + payload.Content["Type"] = uint8(payload.Content["Type"].(float64)) + + err = tpl.Execute(&result, payload.Content) + if err != nil { + logger.WithContext(ctx).Error("[SendEmailLogic] Execute template failed", + logger.Field("error", err.Error()), + logger.Field("data", payload.Content), + ) + return nil + } + content = result.String() + case types.EmailTypeMaintenance: + tpl, _ := template.New("maintenance").Parse(l.svcCtx.Config.Email.MaintenanceEmailTemplate) + var result bytes.Buffer + err = tpl.Execute(&result, payload.Content) + if err != nil { + logger.WithContext(ctx).Error("[SendEmailLogic] Execute template failed", + logger.Field("error", err.Error()), + logger.Field("template", l.svcCtx.Config.Email.MaintenanceEmailTemplate), + logger.Field("data", payload.Content), + ) + return nil + } + content = result.String() + case types.EmailTypeExpiration: + tpl, _ := template.New("expiration").Parse(l.svcCtx.Config.Email.ExpirationEmailTemplate) + var result bytes.Buffer + err = tpl.Execute(&result, payload.Content) + if err != nil { + logger.WithContext(ctx).Error("[SendEmailLogic] Execute template failed", + logger.Field("error", err.Error()), + logger.Field("template", l.svcCtx.Config.Email.ExpirationEmailTemplate), + logger.Field("data", payload.Content), + ) + return nil + } + content = result.String() + case types.EmailTypeTrafficExceed: + tpl, _ := template.New("traffic_exceed").Parse(l.svcCtx.Config.Email.TrafficExceedEmailTemplate) + var result bytes.Buffer + err = tpl.Execute(&result, payload.Content) + if err != nil { + logger.WithContext(ctx).Error("[SendEmailLogic] Execute template failed", + logger.Field("error", err.Error()), + logger.Field("template", l.svcCtx.Config.Email.TrafficExceedEmailTemplate), + logger.Field("data", payload.Content), + ) + return nil + } + content = result.String() + case types.EmailTypeCustom: + if payload.Content == nil { + logger.WithContext(ctx).Error("[SendEmailLogic] Custom email content is empty", + logger.Field("payload", payload), + ) + return nil + } + if tpl, ok := payload.Content["content"].(string); !ok { + logger.WithContext(ctx).Error("[SendEmailLogic] Custom email content is not a string", + logger.Field("payload", payload), + ) + return nil + } else { + content = tpl + } + default: + logger.WithContext(ctx).Error("[SendEmailLogic] Unsupported email type", + logger.Field("type", payload.Type), + logger.Field("payload", payload), + ) + return nil + } + + err = sender.Send([]string{payload.Email}, payload.Subject, content) if err != nil { logger.WithContext(ctx).Error("[SendEmailLogic] Send email failed", logger.Field("error", err.Error())) return nil } messageLog.Status = 1 - if err = l.svcCtx.LogModel.InsertMessageLog(ctx, &messageLog); err != nil { - logger.WithContext(ctx).Error("[SendEmailLogic] InsertMessageLog failed", + emailLog, err := messageLog.Marshal() + if err != nil { + logger.WithContext(ctx).Error("[SendEmailLogic] Marshal message log failed", logger.Field("error", err.Error()), logger.Field("messageLog", messageLog), ) + return nil + } + + if err = l.svcCtx.LogModel.Insert(ctx, &log.SystemLog{ + Type: log.TypeEmailMessage.Uint8(), + Date: time.Now().Format("2006-01-02"), + ObjectID: 0, + Content: string(emailLog), + }); err != nil { + logger.WithContext(ctx).Error("[SendEmailLogic] Insert email log failed", + logger.Field("error", err.Error()), + logger.Field("emailLog", string(emailLog)), + ) + return nil } - logger.WithContext(ctx).Info("[SendEmailLogic] Send email", logger.Field("email", payload.Email), logger.Field("content", payload.Content)) return nil } diff --git a/queue/logic/order/activateOrderLogic.go b/queue/logic/order/activateOrderLogic.go index 39788d7..b920de3 100644 --- a/queue/logic/order/activateOrderLogic.go +++ b/queue/logic/order/activateOrderLogic.go @@ -7,15 +7,17 @@ import ( "encoding/json" "fmt" "strconv" + "strings" "time" + "github.com/perfect-panel/server/internal/model/log" + "github.com/perfect-panel/server/internal/model/node" "github.com/perfect-panel/server/pkg/constant" "github.com/perfect-panel/server/pkg/logger" tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" "github.com/google/uuid" "github.com/hibiken/asynq" - "github.com/perfect-panel/server/internal/config" "github.com/perfect-panel/server/internal/logic/telegram" "github.com/perfect-panel/server/internal/model/order" "github.com/perfect-panel/server/internal/model/subscribe" @@ -44,11 +46,6 @@ const ( OrderStatusFinished = 5 // Order successfully completed ) -// Commission type constants define the types of commission transactions -const ( - CommissionTypeRecharge = 1 // Commission from balance recharge -) - // Predefined error variables for common error conditions var ( ErrInvalidOrderStatus = fmt.Errorf("invalid order status") @@ -81,7 +78,7 @@ func (l *ActivateOrderLogic) ProcessTask(ctx context.Context, task *asynq.Task) return nil // Log and continue } - if err := l.processOrderByType(ctx, orderInfo); err != nil { + if err = l.processOrderByType(ctx, orderInfo); err != nil { logger.WithContext(ctx).Error("[ActivateOrderLogic] Process task failed", logger.Field("error", err.Error())) return nil } @@ -90,7 +87,7 @@ func (l *ActivateOrderLogic) ProcessTask(ctx context.Context, task *asynq.Task) return nil } -// parsePayload unmarshals the task payload into a structured format +// parsePayload unMarshals the task payload into a structured format func (l *ActivateOrderLogic) parsePayload(ctx context.Context, payload []byte) (*types.ForthwithActivateOrderPayload, error) { var p types.ForthwithActivateOrderPayload if err := json.Unmarshal(payload, &p); err != nil { @@ -185,7 +182,7 @@ func (l *ActivateOrderLogic) NewPurchase(ctx context.Context, orderInfo *order.O } // Handle commission in separate goroutine to avoid blocking - go l.handleCommission(context.Background(), userInfo, orderInfo, true) + go l.handleCommission(context.Background(), userInfo, orderInfo) // Clear cache l.clearServerCache(ctx, sub) @@ -280,8 +277,12 @@ func (l *ActivateOrderLogic) getTempOrderInfo(ctx context.Context, orderNo strin } var tempOrder constant.TemporaryOrderInfo - if err = json.Unmarshal([]byte(data), &tempOrder); err != nil { - logger.WithContext(ctx).Error("Unmarshal temp order failed", logger.Field("error", err.Error())) + if err = tempOrder.Unmarshal([]byte(data)); err != nil { + logger.WithContext(ctx).Error("Unmarshal temp order cache failed", + logger.Field("error", err.Error()), + logger.Field("cache_key", cacheKey), + logger.Field("data", data), + ) return nil, err } @@ -352,8 +353,8 @@ func (l *ActivateOrderLogic) createUserSubscription(ctx context.Context, orderIn // handleCommission processes referral commission for the referrer if applicable. // This runs asynchronously to avoid blocking the main order processing flow. -func (l *ActivateOrderLogic) handleCommission(ctx context.Context, userInfo *user.User, orderInfo *order.Order, isNewPurchase bool) { - if !l.shouldProcessCommission(userInfo, orderInfo, isNewPurchase) { +func (l *ActivateOrderLogic) handleCommission(ctx context.Context, userInfo *user.User, orderInfo *order.Order) { + if !l.shouldProcessCommission(userInfo, orderInfo.IsNew) { return } @@ -366,21 +367,45 @@ func (l *ActivateOrderLogic) handleCommission(ctx context.Context, userInfo *use return } - amount := l.calculateCommission(orderInfo.Price) + var referralPercentage uint8 + if referer.ReferralPercentage != 0 { + referralPercentage = referer.ReferralPercentage + } else { + referralPercentage = uint8(l.svc.Config.Invite.ReferralPercentage) + } + + // Order commission calculation: (Order Amount - Order Fee) * Referral Percentage + amount := l.calculateCommission(orderInfo.Amount-orderInfo.FeeAmount, referralPercentage) // Use transaction for commission updates err = l.svc.DB.Transaction(func(tx *gorm.DB) error { referer.Commission += amount - if err := l.svc.UserModel.Update(ctx, referer, tx); err != nil { + if err = l.svc.UserModel.Update(ctx, referer, tx); err != nil { return err } - commissionLog := &user.CommissionLog{ - UserId: referer.Id, - OrderNo: orderInfo.OrderNo, - Amount: amount, + var commissionType uint16 + switch orderInfo.Type { + case OrderTypeSubscribe: + commissionType = log.CommissionTypePurchase + case OrderTypeRenewal: + commissionType = log.CommissionTypeRenewal } - return l.svc.UserModel.InsertCommissionLog(ctx, commissionLog, tx) + + commissionLog := &log.Commission{ + Type: commissionType, + Amount: amount, + OrderNo: orderInfo.OrderNo, + Timestamp: orderInfo.CreatedAt.UnixMilli(), + } + + content, _ := commissionLog.Marshal() + return tx.Model(&log.SystemLog{}).Create(&log.SystemLog{ + Type: log.TypeCommission.Uint8(), + Date: time.Now().Format("2006-01-02"), + ObjectID: referer.Id, + Content: string(content), + }).Error }) if err != nil { @@ -389,7 +414,7 @@ func (l *ActivateOrderLogic) handleCommission(ctx context.Context, userInfo *use } // Update cache - if err := l.svc.UserModel.UpdateUserCache(ctx, referer); err != nil { + if err = l.svc.UserModel.UpdateUserCache(ctx, referer); err != nil { logger.WithContext(ctx).Error("Update referer cache failed", logger.Field("error", err.Error()), logger.Field("user_id", referer.Id), @@ -399,47 +424,60 @@ func (l *ActivateOrderLogic) handleCommission(ctx context.Context, userInfo *use // shouldProcessCommission determines if commission should be processed based on // referrer existence, commission settings, and order type -func (l *ActivateOrderLogic) shouldProcessCommission(userInfo *user.User, orderInfo *order.Order, isNewPurchase bool) bool { - return userInfo.RefererId != 0 && - l.svc.Config.Invite.ReferralPercentage != 0 && - (!l.svc.Config.Invite.OnlyFirstPurchase || (isNewPurchase && orderInfo.IsNew)) +func (l *ActivateOrderLogic) shouldProcessCommission(userInfo *user.User, isFirstPurchase bool) bool { + if userInfo == nil || userInfo.RefererId == 0 { + return false + } + + referer, err := l.svc.UserModel.FindOne(context.Background(), userInfo.RefererId) + if err != nil { + logger.Errorw("Find referer failed", + logger.Field("error", err.Error()), + logger.Field("referer_id", userInfo.RefererId)) + return false + } + if referer == nil { + return false + } + + // use referer's custom settings if set + if referer.ReferralPercentage > 0 { + if referer.OnlyFirstPurchase != nil && *referer.OnlyFirstPurchase && !isFirstPurchase { + return false + } + return true + } + + // use global settings + if l.svc.Config.Invite.ReferralPercentage == 0 { + return false + } + if l.svc.Config.Invite.OnlyFirstPurchase && !isFirstPurchase { + return false + } + + return true } // calculateCommission computes the commission amount based on order price and referral percentage -func (l *ActivateOrderLogic) calculateCommission(price int64) int64 { - return int64(float64(price) * (float64(l.svc.Config.Invite.ReferralPercentage) / 100)) +func (l *ActivateOrderLogic) calculateCommission(price int64, percentage uint8) int64 { + return int64(float64(price) * (float64(percentage) / 100)) } // clearServerCache clears user list cache for all servers associated with the subscription func (l *ActivateOrderLogic) clearServerCache(ctx context.Context, sub *subscribe.Subscribe) { - serverIds := tool.StringToInt64Slice(sub.Server) - groupServerIds := l.getServerIdsByGroups(ctx, sub.ServerGroup) - allServerIds := append(serverIds, groupServerIds...) + nodeIds := tool.StringToInt64Slice(sub.Nodes) + tags := strings.Split(sub.NodeTags, ",") - for _, id := range allServerIds { - cacheKey := fmt.Sprintf("%s%d", config.ServerUserListCacheKey, id) - if err := l.svc.Redis.Del(ctx, cacheKey).Err(); err != nil { - logger.WithContext(ctx).Error("Del server user list cache failed", - logger.Field("error", err.Error()), - logger.Field("cache_key", cacheKey), - ) - } - } -} - -// getServerIdsByGroups retrieves server IDs from server groups -func (l *ActivateOrderLogic) getServerIdsByGroups(ctx context.Context, serverGroup string) []int64 { - data, err := l.svc.ServerModel.FindServerListByGroupIds(ctx, tool.StringToInt64Slice(serverGroup)) + err := l.svc.NodeModel.ClearNodeCache(ctx, &node.FilterNodeParams{ + Page: 1, + Size: 1000, + ServerId: nodeIds, + Tag: tags, + }) if err != nil { - logger.WithContext(ctx).Error("Find server list failed", logger.Field("error", err.Error())) - return nil + logger.WithContext(ctx).Error("[Order Queue] Clear node cache failed", logger.Field("error", err.Error())) } - - serverIds := make([]int64, len(data)) - for i, item := range data { - serverIds[i] = item.Id - } - return serverIds } // Renewal handles subscription renewal including subscription extension, @@ -460,7 +498,7 @@ func (l *ActivateOrderLogic) Renewal(ctx context.Context, orderInfo *order.Order return err } - if err := l.updateSubscriptionForRenewal(ctx, userSub, sub, orderInfo); err != nil { + if err = l.updateSubscriptionForRenewal(ctx, userSub, sub, orderInfo); err != nil { return err } @@ -478,7 +516,7 @@ func (l *ActivateOrderLogic) Renewal(ctx context.Context, orderInfo *order.Order l.clearServerCache(ctx, sub) // Handle commission - go l.handleCommission(context.Background(), userInfo, orderInfo, false) + go l.handleCommission(context.Background(), userInfo, orderInfo) // Send notifications l.sendNotifications(ctx, orderInfo, userInfo, sub, userSub, telegram.RenewalNotify) @@ -573,6 +611,24 @@ func (l *ActivateOrderLogic) ResetTraffic(ctx context.Context, orderInfo *order. // Clear cache l.clearServerCache(ctx, sub) + // insert reset traffic log + resetLog := &log.ResetSubscribe{ + Type: log.ResetSubscribeTypePaid, + UserId: userInfo.Id, + OrderNo: orderInfo.OrderNo, + Timestamp: time.Now().UnixMilli(), + } + + content, _ := resetLog.Marshal() + if err = l.svc.LogModel.Insert(ctx, &log.SystemLog{ + Type: log.TypeResetSubscribe.Uint8(), + Date: time.Now().Format(time.DateOnly), + ObjectID: userSub.Id, + Content: string(content), + }); err != nil { + logger.WithContext(ctx).Error("[Order Queue]Insert reset subscribe log failed", logger.Field("error", err.Error())) + } + // Send notifications l.sendNotifications(ctx, orderInfo, userInfo, sub, userSub, telegram.ResetTrafficNotify) @@ -590,22 +646,35 @@ func (l *ActivateOrderLogic) Recharge(ctx context.Context, orderInfo *order.Orde // Update balance in transaction err = l.svc.DB.Transaction(func(tx *gorm.DB) error { userInfo.Balance += orderInfo.Price - if err := l.svc.UserModel.Update(ctx, userInfo, tx); err != nil { + if err = l.svc.UserModel.Update(ctx, userInfo, tx); err != nil { return err } - balanceLog := &user.BalanceLog{ - UserId: orderInfo.UserId, - Amount: orderInfo.Price, - Type: CommissionTypeRecharge, - OrderId: orderInfo.Id, - Balance: userInfo.Balance, + balanceLog := &log.Balance{ + Amount: orderInfo.Price, + Type: log.BalanceTypeRecharge, + OrderNo: orderInfo.OrderNo, + Balance: userInfo.Balance, + Timestamp: time.Now().UnixMilli(), } - return l.svc.UserModel.InsertBalanceLog(ctx, balanceLog, tx) + content, _ := balanceLog.Marshal() + + return tx.Model(&log.Balance{}).Create(&log.SystemLog{ + Type: log.TypeBalance.Uint8(), + Date: time.Now().Format("2006-01-02"), + ObjectID: userInfo.Id, + Content: string(content), + }).Error }) if err != nil { - logger.WithContext(ctx).Error("Database transaction failed", logger.Field("error", err.Error())) + logger.WithContext(ctx).Error("[Recharge] Database transaction failed", logger.Field("error", err.Error())) + return err + } + + // clear user cache + if err = l.svc.UserModel.UpdateUserCache(ctx, userInfo); err != nil { + logger.WithContext(ctx).Error("[Recharge] Update user cache failed", logger.Field("error", err.Error())) return err } diff --git a/queue/logic/sms/sendSmsLogic.go b/queue/logic/sms/sendSmsLogic.go index 196309b..76cef6d 100644 --- a/queue/logic/sms/sendSmsLogic.go +++ b/queue/logic/sms/sendSmsLogic.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "time" "github.com/perfect-panel/server/pkg/logger" @@ -43,17 +44,16 @@ func (l *SendSmsLogic) ProcessTask(ctx context.Context, task *asynq.Task) error logger.WithContext(ctx).Error("[SendSmsLogic] New send sms client failed", logger.Field("error", err.Error()), logger.Field("payload", payload)) return err } - createSms := &log.MessageLog{ - Type: log.Mobile.String(), + createSms := &log.Message{ Platform: l.svcCtx.Config.Mobile.Platform, To: fmt.Sprintf("+%s%s", payload.TelephoneArea, payload.Telephone), Subject: constant.ParseVerifyType(payload.Type).String(), - Content: "", + Content: map[string]interface{}{ + "content": client.GetSendCodeContent(payload.Content), + }, } err = client.SendCode(payload.TelephoneArea, payload.Telephone, payload.Content) - createSms.Content = client.GetSendCodeContent(payload.Content) - if err != nil { logger.WithContext(ctx).Error("[SendSmsLogic] Send sms failed", logger.Field("error", err.Error()), logger.Field("payload", payload)) if l.svcCtx.Config.Model != constant.DevMode { @@ -64,7 +64,14 @@ func (l *SendSmsLogic) ProcessTask(ctx context.Context, task *asynq.Task) error } createSms.Status = 1 logger.WithContext(ctx).Info("[SendSmsLogic] Send sms", logger.Field("telephone", payload.Telephone), logger.Field("content", createSms.Content)) - err = l.svcCtx.LogModel.InsertMessageLog(ctx, createSms) + + content, _ := createSms.Marshal() + err = l.svcCtx.LogModel.Insert(ctx, &log.SystemLog{ + Type: log.TypeMobileMessage.Uint8(), + Date: time.Now().Format("2006-01-02"), + ObjectID: 0, + Content: string(content), + }) if err != nil { logger.WithContext(ctx).Error("[SendSmsLogic] Send sms failed", logger.Field("error", err.Error()), logger.Field("payload", payload)) return nil diff --git a/queue/logic/subscription/checkSubscriptionLogic.go b/queue/logic/subscription/checkSubscriptionLogic.go index ef77130..c331de8 100644 --- a/queue/logic/subscription/checkSubscriptionLogic.go +++ b/queue/logic/subscription/checkSubscriptionLogic.go @@ -1,12 +1,13 @@ package subscription import ( - "bytes" "context" "encoding/json" - "text/template" + "strings" "time" + "github.com/perfect-panel/server/internal/model/node" + "github.com/perfect-panel/server/pkg/tool" queue "github.com/perfect-panel/server/queue/types" "github.com/perfect-panel/server/pkg/logger" @@ -62,7 +63,7 @@ func (l *CheckSubscriptionLogic) ProcessTask(ctx context.Context, _ *asynq.Task) return err } } - + l.clearServerCache(ctx, list...) logger.Infow("[Check Subscription Traffic] Update subscribe status", logger.Field("user_ids", ids), logger.Field("count", int64(len(ids)))) } else { @@ -104,6 +105,8 @@ func (l *CheckSubscriptionLogic) ProcessTask(ctx context.Context, _ *asynq.Task) logger.Errorw("[Check Subscription Traffic] Clear subscribe cache failed", logger.Field("error", err.Error())) return err } + l.clearServerCache(ctx, list...) + logger.Info("[Check Subscription Expire] Update subscribe status", logger.Field("user_ids", ids), logger.Field("count", int64(len(ids)))) } else { logger.Info("[Check Subscription Expire] No subscribe need to update") @@ -129,24 +132,14 @@ func (l *CheckSubscriptionLogic) sendExpiredNotify(ctx context.Context, subs []i continue } var taskPayload queue.SendEmailPayload + taskPayload.Type = queue.EmailTypeExpiration taskPayload.Email = method.AuthIdentifier taskPayload.Subject = "Subscription Expired" - tpl, err := template.New("Expired").Parse(l.svc.Config.Email.ExpirationEmailTemplate) - if err != nil { - logger.Errorw("[CheckSubscription] Parse template failed", logger.Field("error", err.Error())) - continue - } - var result bytes.Buffer - err = tpl.Execute(&result, map[string]interface{}{ + taskPayload.Content = map[string]interface{}{ "SiteLogo": l.svc.Config.Site.SiteLogo, "SiteName": l.svc.Config.Site.SiteName, "ExpireDate": sub.ExpireTime.Format("2006-01-02 15:04:05"), - }) - if err != nil { - logger.Errorw("[CheckSubscription] Execute template failed", logger.Field("error", err.Error())) - continue } - taskPayload.Content = result.String() payloadBuy, err := json.Marshal(taskPayload) if err != nil { logger.Errorw("[CheckSubscription] Marshal payload failed", logger.Field("error", err.Error())) @@ -179,23 +172,13 @@ func (l *CheckSubscriptionLogic) sendTrafficNotify(ctx context.Context, subs []i continue } var taskPayload queue.SendEmailPayload + taskPayload.Type = queue.EmailTypeTrafficExceed taskPayload.Email = method.AuthIdentifier taskPayload.Subject = "Subscription Traffic Exceed" - tpl, err := template.New("Traffic").Parse(l.svc.Config.Email.TrafficExceedEmailTemplate) - if err != nil { - logger.Errorw("[CheckSubscription] Parse template failed", logger.Field("error", err.Error())) - continue - } - var result bytes.Buffer - err = tpl.Execute(&result, map[string]interface{}{ + taskPayload.Content = map[string]interface{}{ "SiteLogo": l.svc.Config.Site.SiteLogo, "SiteName": l.svc.Config.Site.SiteName, - }) - if err != nil { - logger.Errorw("[CheckSubscription] Execute template failed", logger.Field("error", err.Error())) - continue } - taskPayload.Content = result.String() payloadBuy, err := json.Marshal(taskPayload) if err != nil { logger.Errorw("[CheckSubscription] Marshal payload failed", logger.Field("error", err.Error())) @@ -214,3 +197,41 @@ func (l *CheckSubscriptionLogic) sendTrafficNotify(ctx context.Context, subs []i } return nil } + +func (l *CheckSubscriptionLogic) clearServerCache(ctx context.Context, userSubs ...*user.Subscribe) { + subs := make(map[int64]bool) + for _, sub := range userSubs { + if _, ok := subs[sub.SubscribeId]; !ok { + subs[sub.SubscribeId] = true + } + } + + for sub, _ := range subs { + info, err := l.svc.SubscribeModel.FindOne(ctx, sub) + if err != nil { + logger.Errorw("[CheckSubscription] FindOne subscribe failed", logger.Field("error", err.Error()), logger.Field("subscribe_id", sub)) + continue + } + if info != nil && info.Id == sub { + var nodes []int64 + if info.Nodes != "" { + nodes = tool.StringToInt64Slice(info.Nodes) + } + var tag []string + if info.NodeTags != "" { + tag = strings.Split(info.NodeTags, ",") + } + + err = l.svc.NodeModel.ClearNodeCache(ctx, &node.FilterNodeParams{ + Page: 1, + Size: 1000, + Tag: tag, + ServerId: nodes, + }) + if err != nil { + logger.Errorw("[CheckSubscription] ClearNodeCache failed", logger.Field("error", err.Error()), logger.Field("subscribe_id", sub)) + continue + } + } + } +} diff --git a/queue/logic/task/quotaLogic.go b/queue/logic/task/quotaLogic.go new file mode 100644 index 0000000..4fd9632 --- /dev/null +++ b/queue/logic/task/quotaLogic.go @@ -0,0 +1,450 @@ +package task + +import ( + "context" + "encoding/json" + "fmt" + "strconv" + "time" + + "github.com/hibiken/asynq" + "github.com/perfect-panel/server/internal/model/log" + "github.com/perfect-panel/server/internal/model/order" + "github.com/perfect-panel/server/internal/model/subscribe" + "github.com/perfect-panel/server/internal/model/task" + "github.com/perfect-panel/server/internal/model/user" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/tool" + "gorm.io/gorm" +) + +const ( + UnitTimeNoLimit = "NoLimit" // Unlimited time subscription + UnitTimeYear = "Year" // Annual subscription + UnitTimeMonth = "Month" // Monthly subscription + UnitTimeDay = "Day" // Daily subscription + UnitTimeHour = "Hour" // Hourly subscription + UnitTimeMinute = "Minute" // Per-minute subscription + +) + +type QuotaTaskLogic struct { + svcCtx *svc.ServiceContext +} + +type ErrorInfo struct { + UserSubscribeId int64 `json:"user_subscribe_id"` + Error string `json:"error"` +} + +func NewQuotaTaskLogic(svcCtx *svc.ServiceContext) *QuotaTaskLogic { + return &QuotaTaskLogic{ + svcCtx: svcCtx, + } +} + +func (l *QuotaTaskLogic) ProcessTask(ctx context.Context, t *asynq.Task) error { + taskID, err := l.parseTaskID(ctx, t.Payload()) + if err != nil { + return err + } + + taskInfo, err := l.getTaskInfo(ctx, taskID) + if err != nil { + return err + } + + if taskInfo.Status != 0 { + logger.WithContext(ctx).Info("[QuotaTaskLogic.ProcessTask] task already processed", + logger.Field("taskID", taskID), + logger.Field("status", taskInfo.Status), + ) + return nil + } + + scope, content, err := l.parseTaskData(ctx, taskInfo) + if err != nil { + return err + } + + subscribes, err := l.getSubscribes(ctx, scope.Objects) + if err != nil { + return err + } + if err = l.processSubscribes(ctx, subscribes, content, taskInfo); err != nil { + return err + } + // 清理用户缓存(仅在有赠送金时清理) + if content.GiftValue != 0 { + var userIds []int64 + for _, sub := range subscribes { + userIds = append(userIds, sub.UserId) + } + userIds = tool.RemoveDuplicateElements(userIds...) + var users []*user.User + if err = l.svcCtx.DB.WithContext(ctx).Model(&user.User{}).Where("id IN ?", userIds).Find(&users).Error; err != nil { + logger.WithContext(ctx).Error("[QuotaTaskLogic.ProcessTask] find users error", + logger.Field("error", err.Error()), + logger.Field("userIDs", userIds)) + } + err = l.svcCtx.UserModel.ClearUserCache(ctx, users...) + if err != nil { + logger.WithContext(ctx).Error("[QuotaTaskLogic.ProcessTask] clear user cache error", + logger.Field("error", err.Error()), + logger.Field("userIDs", userIds)) + } + } + + // 清理用户订阅缓存 + err = l.svcCtx.UserModel.ClearSubscribeCache(ctx, subscribes...) + if err != nil { + logger.WithContext(ctx).Error("[QuotaTaskLogic.ProcessTask] clear subscribe cache error", + logger.Field("error", err.Error())) + } + + return nil +} + +func (l *QuotaTaskLogic) parseTaskID(ctx context.Context, payload []byte) (int64, error) { + if len(payload) == 0 { + logger.WithContext(ctx).Error("[QuotaTaskLogic.parseTaskID] empty payload") + return 0, asynq.SkipRetry + } + + taskID, err := strconv.ParseInt(string(payload), 10, 64) + if err != nil { + logger.WithContext(ctx).Error("[QuotaTaskLogic.parseTaskID] invalid task ID", + logger.Field("error", err.Error()), + logger.Field("payload", string(payload)), + ) + return 0, asynq.SkipRetry + } + return taskID, nil +} + +func (l *QuotaTaskLogic) getTaskInfo(ctx context.Context, taskID int64) (*task.Task, error) { + var taskInfo *task.Task + if err := l.svcCtx.DB.WithContext(ctx).Model(&task.Task{}).Where("id = ?", taskID).First(&taskInfo).Error; err != nil { + logger.WithContext(ctx).Error("[QuotaTaskLogic.getTaskInfo] find task error", + logger.Field("error", err.Error()), + logger.Field("taskID", taskID), + ) + return nil, asynq.SkipRetry + } + return taskInfo, nil +} + +func (l *QuotaTaskLogic) parseTaskData(ctx context.Context, taskInfo *task.Task) (task.QuotaScope, task.QuotaContent, error) { + var scope task.QuotaScope + if err := scope.Unmarshal([]byte(taskInfo.Scope)); err != nil { + logger.WithContext(ctx).Error("[QuotaTaskLogic.parseTaskData] unmarshal scope error", + logger.Field("error", err.Error()), + ) + return scope, task.QuotaContent{}, asynq.SkipRetry + } + + var content task.QuotaContent + if err := content.Unmarshal([]byte(taskInfo.Content)); err != nil { + logger.WithContext(ctx).Error("[QuotaTaskLogic.parseTaskData] unmarshal content error", + logger.Field("error", err.Error()), + ) + return scope, content, asynq.SkipRetry + } + return scope, content, nil +} + +func (l *QuotaTaskLogic) getSubscribes(ctx context.Context, subscriberIDs []int64) ([]*user.Subscribe, error) { + var subscribes []*user.Subscribe + if err := l.svcCtx.DB.WithContext(ctx).Model(&user.Subscribe{}).Where("id IN ?", subscriberIDs).Find(&subscribes).Error; err != nil { + logger.WithContext(ctx).Error("[QuotaTaskLogic.getSubscribes] find subscribes error", + logger.Field("error", err.Error()), + logger.Field("subscribers", subscriberIDs), + ) + return nil, asynq.SkipRetry + } + return subscribes, nil +} + +func (l *QuotaTaskLogic) processSubscribes(ctx context.Context, subscribes []*user.Subscribe, content task.QuotaContent, taskInfo *task.Task) error { + tx := l.svcCtx.DB.WithContext(ctx).Begin() + defer func() { + if r := recover(); r != nil { + tx.Rollback() + logger.WithContext(ctx).Error("[QuotaTaskLogic.processSubscribes] transaction panic", + logger.Field("panic", r), + ) + } + }() + + var errors []ErrorInfo + now := time.Now() + + for _, sub := range subscribes { + if err := l.processSubscription(tx, sub, content, now, &errors); err != nil { + tx.Rollback() + return err + } + } + + // 根据错误情况决定任务状态 + status := int8(2) // Completed + if len(errors) > 0 { + logger.WithContext(ctx).Error("[QuotaTaskLogic.processSubscribes] some subscriptions failed", + logger.Field("total", len(subscribes)), + logger.Field("failed", len(errors)), + ) + // 如果所有订阅都失败,标记为失败状态 + if len(errors) == len(subscribes) { + status = 3 // Failed + } + errs, err := json.Marshal(errors) + if err != nil { + logger.WithContext(ctx).Error("[QuotaTaskLogic.processSubscribes] marshal errors failed", + logger.Field("error", err.Error()), + ) + tx.Rollback() + return err + } + taskInfo.Errors = string(errs) + } + + taskInfo.Current = uint64(len(subscribes)) + taskInfo.Status = status + err := tx.Where("id = ?", taskInfo.Id).Save(taskInfo).Error + if err != nil { + logger.WithContext(ctx).Error("[QuotaTaskLogic.processSubscribes] update task status error", + logger.Field("error", err.Error()), + logger.Field("taskID", taskInfo.Id), + ) + tx.Rollback() + return err + } + + if err = tx.Commit().Error; err != nil { + logger.WithContext(ctx).Error("[QuotaTaskLogic.processSubscribes] commit transaction error", + logger.Field("error", err.Error()), + ) + return err + } + + return nil +} + +func (l *QuotaTaskLogic) processSubscription(tx *gorm.DB, sub *user.Subscribe, content task.QuotaContent, now time.Time, errors *[]ErrorInfo) error { + // 验证订阅数据 + if sub == nil { + *errors = append(*errors, ErrorInfo{ + UserSubscribeId: 0, + Error: "subscription is nil", + }) + return nil + } + + updated := false + + // 处理时间延长 - 修复逻辑:只要Days不为0就处理,不管ExpireTime是否为0 + if content.Days != 0 { + if sub.ExpireTime.Unix() == 0 || sub.ExpireTime.Before(now) { + // 如果没有过期时间或已过期,从现在开始计算 + sub.ExpireTime = now.AddDate(0, 0, int(content.Days)) + } else { + // 在原有过期时间基础上延长 + sub.ExpireTime = sub.ExpireTime.AddDate(0, 0, int(content.Days)) + } + // 如果订阅延长到未来时间,设置为激活状态 + if sub.ExpireTime.After(now) && sub.Status != 1 { + sub.Status = 1 // Active + } + updated = true + } + + // 处理流量重置 + if content.ResetTraffic { + sub.Download = 0 + sub.Upload = 0 + updated = true + if err := l.createResetTrafficLog(tx, sub.Id, sub.UserId, now); err != nil { + // 记录错误但不阻断整个任务,日志失败不影响主流程 + *errors = append(*errors, ErrorInfo{ + UserSubscribeId: sub.Id, + Error: "create reset traffic log error: " + err.Error(), + }) + } + } + + // 处理赠送金 + if content.GiftValue != 0 { + if err := l.processGift(tx, sub, content, now, errors); err != nil { + return err + } + } + + // 只有在有更新时才保存订阅信息 + if updated { + if err := tx.Where("id = ?", sub.Id).Save(sub).Error; err != nil { + *errors = append(*errors, ErrorInfo{ + UserSubscribeId: sub.Id, + Error: "update subscription error: " + err.Error(), + }) + return nil + } + } + + return nil +} + +func (l *QuotaTaskLogic) processGift(tx *gorm.DB, sub *user.Subscribe, content task.QuotaContent, now time.Time, errors *[]ErrorInfo) error { + // 验证赠送类型 + if content.GiftType != 1 && content.GiftType != 2 { + *errors = append(*errors, ErrorInfo{ + UserSubscribeId: sub.Id, + Error: fmt.Sprintf("invalid gift type: %d", content.GiftType), + }) + return nil + } + + var userInfo user.User + if err := tx.Model(&user.User{}).Where("id = ?", sub.UserId).First(&userInfo).Error; err != nil { + *errors = append(*errors, ErrorInfo{ + UserSubscribeId: sub.Id, + Error: "find user error: " + err.Error(), + }) + return nil + } + + var giftAmount int64 + switch content.GiftType { + case 1: + giftAmount = int64(content.GiftValue) + case 2: + orderAmount, err := l.calculateOrderAmount(tx, sub, now) + if err != nil { + *errors = append(*errors, ErrorInfo{ + UserSubscribeId: sub.Id, + Error: err.Error(), + }) + return nil + } + if orderAmount > 0 { + giftAmount = int64(float64(orderAmount) * (float64(content.GiftValue) / 100)) + } + } + + if giftAmount > 0 { + userInfo.GiftAmount += giftAmount + // 使用Update而不是Save,更精确地更新单个字段 + if err := tx.Model(&user.User{}).Where("id = ?", sub.UserId).Update("gift_amount", userInfo.GiftAmount).Error; err != nil { + *errors = append(*errors, ErrorInfo{ + UserSubscribeId: sub.Id, + Error: "update user gift amount error: " + err.Error(), + }) + return nil + } + + if err := l.createGiftLog(tx, sub.Id, userInfo.Id, giftAmount, userInfo.GiftAmount, now); err != nil { + *errors = append(*errors, ErrorInfo{ + UserSubscribeId: sub.Id, + Error: "create gift log error: " + err.Error(), + }) + // 回滚用户金额更新 + userInfo.GiftAmount -= giftAmount + tx.Model(&user.User{}).Where("id = ?", sub.UserId).Update("gift_amount", userInfo.GiftAmount) + return nil + } + } + + return nil +} + +func (l *QuotaTaskLogic) getStartTime(sub *user.Subscribe, now time.Time) time.Time { + if sub.StartTime.Unix() == 0 { + return now + } + return sub.StartTime +} + +func (l *QuotaTaskLogic) calculateOrderAmount(tx *gorm.DB, sub *user.Subscribe, now time.Time) (int64, error) { + if sub.OrderId != 0 { + var orderInfo *order.Order + if err := tx.Model(&order.Order{}).Where("id = ?", sub.OrderId).First(&orderInfo).Error; err != nil { + return 0, fmt.Errorf("find order error: %v", err) + } + return orderInfo.Amount + orderInfo.GiftAmount, nil + } + + var subInfo *subscribe.Subscribe + if err := tx.Model(&subscribe.Subscribe{}).Where("id = ?", sub.SubscribeId).First(&subInfo).Error; err != nil { + return 0, fmt.Errorf("find subscribe error: %v", err) + } + + startTime := l.getStartTime(sub, now) + if sub.ExpireTime.Before(startTime) { + return subInfo.UnitPrice, nil + } + + switch subInfo.UnitTime { + case UnitTimeNoLimit: + return subInfo.UnitPrice, nil + case UnitTimeYear: + days := tool.DayDiff(startTime, sub.ExpireTime) + return subInfo.UnitPrice / 365 * days, nil + case UnitTimeMonth: + days := tool.DayDiff(startTime, sub.ExpireTime) + return subInfo.UnitPrice / 30 * days, nil + case UnitTimeDay: + days := tool.DayDiff(startTime, sub.ExpireTime) + return subInfo.UnitPrice * days, nil + case UnitTimeHour: + hours := int(tool.HourDiff(startTime, sub.ExpireTime)) + return subInfo.UnitPrice * int64(hours), nil + case UnitTimeMinute: + minutes := tool.HourDiff(startTime, sub.ExpireTime) * 60 + return subInfo.UnitPrice * minutes, nil + default: + return subInfo.UnitPrice, nil + } +} + +func (l *QuotaTaskLogic) createGiftLog(tx *gorm.DB, subscribeId, userId, amount, balance int64, now time.Time) error { + giftLog := &log.Gift{ + Type: log.GiftTypeIncrease, + OrderNo: "", + SubscribeId: subscribeId, + Amount: amount, + Balance: balance, + Remark: "Quota task gift", + Timestamp: now.UnixMilli(), + } + + logString, err := giftLog.Marshal() + if err != nil { + return fmt.Errorf("marshal gift log error: %v", err) + } + return tx.Model(&log.SystemLog{}).Create(&log.SystemLog{ + Type: log.TypeGift.Uint8(), + Content: string(logString), + ObjectID: userId, + Date: now.Format(time.DateOnly), + }).Error +} + +func (l *QuotaTaskLogic) createResetTrafficLog(tx *gorm.DB, subscribeId, userId int64, now time.Time) error { + trafficLog := &log.ResetSubscribe{ + Type: log.ResetSubscribeTypeQuota, + UserId: userId, + OrderNo: "", + Timestamp: now.UnixMilli(), + } + + logString, err := trafficLog.Marshal() + if err != nil { + return fmt.Errorf("marshal traffic log error: %v", err) + } + return tx.Model(&log.SystemLog{}).Create(&log.SystemLog{ + Type: log.TypeResetSubscribe.Uint8(), + Content: string(logString), + ObjectID: subscribeId, + Date: now.Format(time.DateOnly), + }).Error +} diff --git a/queue/logic/traffic/resetTrafficLogic.go b/queue/logic/traffic/resetTrafficLogic.go index 9aa09f8..8f4f525 100644 --- a/queue/logic/traffic/resetTrafficLogic.go +++ b/queue/logic/traffic/resetTrafficLogic.go @@ -8,10 +8,13 @@ import ( "strings" "time" + "github.com/perfect-panel/server/internal/model/log" + "github.com/perfect-panel/server/internal/model/node" "github.com/perfect-panel/server/internal/model/subscribe" "github.com/perfect-panel/server/internal/model/user" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/tool" "github.com/perfect-panel/server/queue/types" "github.com/hibiken/asynq" @@ -116,13 +119,6 @@ func (l *ResetTrafficLogic) ProcessTask(ctx context.Context, _ *asynq.Task) erro } }() - // Reset today's traffic data - err = l.svc.NodeCache.ResetTodayTrafficData(ctx) - if err != nil { - logger.Errorw("[ResetTodayTraffic] Failed to reset today traffic data", - logger.Field("error", err.Error())) - } - // Load last reset time from cache var cache resetTrafficCache cacheData, err := l.svc.Redis.Get(ctx, cacheKey).Result() @@ -237,8 +233,10 @@ func (l *ResetTrafficLogic) resetMonth(ctx context.Context) error { err = db.Model(&user.Subscribe{}).Where("`id` IN ?", monthlyResetUsers). Updates(map[string]interface{}{ - "upload": 0, - "download": 0, + "upload": 0, + "download": 0, + "status": 1, // Ensure status is active + "finished_at": nil, }).Error if err != nil { logger.Errorw("[ResetTraffic] Failed to update monthly reset users", logger.Field("error", err.Error())) @@ -252,16 +250,7 @@ func (l *ResetTrafficLogic) resetMonth(ctx context.Context) error { return err } // Clear cache for these subscriptions - for _, sub := range userSubs { - if sub.SubscribeId > 0 { - err = l.svc.UserModel.ClearSubscribeCache(ctx, sub) - if err != nil { - logger.Errorw("[ResetTraffic] Failed to clear cache for subscription", - logger.Field("subscribeId", sub.SubscribeId), - logger.Field("error", err.Error())) - } - } - } + l.clearCache(ctx, userSubs) logger.Infow("[ResetTraffic] Monthly reset completed", logger.Field("count", len(monthlyResetUsers))) } else { logger.Infow("[ResetTraffic] No users found for monthly reset") @@ -329,8 +318,10 @@ func (l *ResetTrafficLogic) reset1st(ctx context.Context, cache resetTrafficCach // Reset upload and download traffic to zero err = db.Model(&user.Subscribe{}).Where("`id` IN ?", users1stReset). Updates(map[string]interface{}{ - "upload": 0, - "download": 0, + "upload": 0, + "download": 0, + "status": 1, // Ensure status is active + "finished_at": nil, }).Error if err != nil { logger.Errorw("[ResetTraffic] Failed to update 1st reset users", logger.Field("error", err.Error())) @@ -344,17 +335,7 @@ func (l *ResetTrafficLogic) reset1st(ctx context.Context, cache resetTrafficCach } // Clear cache for these subscriptions - for _, sub := range userSubs { - if sub.SubscribeId > 0 { - err = l.svc.UserModel.ClearSubscribeCache(ctx, sub) - if err != nil { - logger.Errorw("[ResetTraffic] Failed to clear cache for subscription", - logger.Field("subscribeId", sub.SubscribeId), - logger.Field("error", err.Error())) - } - } - } - + l.clearCache(ctx, userSubs) logger.Infow("[ResetTraffic] 1st reset completed", logger.Field("count", len(users1stReset))) } else { logger.Infow("[ResetTraffic] No users found for 1st reset") @@ -423,8 +404,10 @@ func (l *ResetTrafficLogic) resetYear(ctx context.Context) error { // Reset upload and download traffic to zero err = db.Model(&user.Subscribe{}).Where("`id` IN ?", usersYearReset). Updates(map[string]interface{}{ - "upload": 0, - "download": 0, + "upload": 0, + "download": 0, + "status": 1, // Ensure status is active + "finished_at": nil, }).Error if err != nil { logger.Errorw("[ResetTraffic] Failed to update yearly reset users", logger.Field("error", err.Error())) @@ -438,16 +421,7 @@ func (l *ResetTrafficLogic) resetYear(ctx context.Context) error { return err } // Clear cache for these subscriptions - for _, sub := range userSubs { - if sub.SubscribeId > 0 { - err = l.svc.UserModel.ClearSubscribeCache(ctx, sub) - if err != nil { - logger.Errorw("[ResetTraffic] Failed to clear cache for subscription", - logger.Field("subscribeId", sub.SubscribeId), - logger.Field("error", err.Error())) - } - } - } + l.clearCache(ctx, userSubs) logger.Infow("[ResetTraffic] Yearly reset completed", logger.Field("count", len(usersYearReset))) } else { logger.Infow("[ResetTraffic] No users found for yearly reset") @@ -601,3 +575,73 @@ func (l *ResetTrafficLogic) isRetryableError(err error) bool { logger.Field("error", err.Error())) return true } + +// clearCache clears the reset traffic cache +func (l *ResetTrafficLogic) clearCache(ctx context.Context, list []*user.Subscribe) { + if len(list) != 0 { + subs := make(map[int64]bool) + + for _, sub := range list { + if sub.SubscribeId > 0 { + err := l.svc.UserModel.ClearSubscribeCache(ctx, sub) + if err != nil { + logger.Errorw("[ResetTraffic] Failed to clear cache for subscription", + logger.Field("subscribeId", sub.SubscribeId), + logger.Field("error", err.Error())) + } + if _, ok := subs[sub.SubscribeId]; !ok { + subs[sub.SubscribeId] = true + } + } + // Insert traffic reset log + l.insertLog(ctx, sub.Id, sub.UserId) + } + + for sub, _ := range subs { + info, err := l.svc.SubscribeModel.FindOne(ctx, sub) + if err != nil { + logger.Errorw("[CheckSubscription] FindOne subscribe failed", logger.Field("error", err.Error()), logger.Field("subscribe_id", sub)) + continue + } + if info != nil && info.Id == sub { + var nodes []int64 + if info.Nodes != "" { + nodes = tool.StringToInt64Slice(info.Nodes) + } + var tag []string + if info.NodeTags != "" { + tag = strings.Split(info.NodeTags, ",") + } + + err = l.svc.NodeModel.ClearNodeCache(ctx, &node.FilterNodeParams{ + Page: 1, + Size: 1000, + Tag: tag, + ServerId: nodes, + }) + if err != nil { + logger.Errorw("[CheckSubscription] ClearNodeCache failed", logger.Field("error", err.Error()), logger.Field("subscribe_id", sub)) + continue + } + } + } + } +} + +// insertLog inserts a reset traffic log entry +func (l *ResetTrafficLogic) insertLog(ctx context.Context, subId, userId int64) { + trafficLog := log.ResetSubscribe{ + Type: log.ResetSubscribeTypeAuto, + UserId: userId, + Timestamp: time.Now().UnixMilli(), + } + content, _ := trafficLog.Marshal() + if err := l.svc.DB.WithContext(ctx).Model(&log.SystemLog{}).Create(&log.SystemLog{ + Type: log.TypeResetSubscribe.Uint8(), + ObjectID: subId, + Date: time.Now().Format(time.DateOnly), + Content: string(content), + }).Error; err != nil { + logger.Errorw("[ResetTraffic] Failed to create system log for subscription", logger.Field("error", err.Error())) + } +} diff --git a/queue/logic/traffic/serverDataLogic.go b/queue/logic/traffic/serverDataLogic.go index 98fbaba..f8ca675 100644 --- a/queue/logic/traffic/serverDataLogic.go +++ b/queue/logic/traffic/serverDataLogic.go @@ -73,7 +73,7 @@ func (l *ServerDataLogic) getRanking(ctx context.Context) (top10ServerToday, top if s.ServerId == 0 { continue } - serverInfo, err := l.svc.ServerModel.FindOne(ctx, s.ServerId) + serverInfo, err := l.svc.NodeModel.FindOneServer(ctx, s.ServerId) if err != nil { logger.Error("[ServerDataLogic] Find server failed", logger.Field("error", err.Error())) continue @@ -92,7 +92,7 @@ func (l *ServerDataLogic) getRanking(ctx context.Context) (top10ServerToday, top logger.Error("[ServerDataLogic] Get top servers traffic by day failed", logger.Field("error", err.Error())) } else { for _, s := range serverYesterday { - serverInfo, err := l.svc.ServerModel.FindOne(ctx, s.ServerId) + serverInfo, err := l.svc.NodeModel.FindOneServer(ctx, s.ServerId) if err != nil { logger.Error("[ServerDataLogic] Find server failed", logger.Field("error", err.Error())) continue diff --git a/queue/logic/traffic/trafficStatLogic.go b/queue/logic/traffic/trafficStatLogic.go new file mode 100644 index 0000000..81a422b --- /dev/null +++ b/queue/logic/traffic/trafficStatLogic.go @@ -0,0 +1,176 @@ +package traffic + +import ( + "context" + "time" + + "github.com/hibiken/asynq" + "github.com/perfect-panel/server/internal/model/log" + "github.com/perfect-panel/server/internal/model/traffic" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/pkg/logger" +) + +type StatLogic struct { + svc *svc.ServiceContext +} + +func NewStatLogic(svc *svc.ServiceContext) *StatLogic { + return &StatLogic{ + svc: svc, + } +} + +func (l *StatLogic) ProcessTask(ctx context.Context, _ *asynq.Task) error { + now := time.Now() + tx := l.svc.DB.Begin() + var err error + defer func(err error) { + if err != nil { + logger.Errorf("[Traffic Stat Queue] Process task failed: %v", err.Error()) + tx.Rollback() + } else { + logger.Infof("[Traffic Stat Queue] Process task completed successfully, consuming: %s", time.Since(now).String()) + // 提交事务 + if err = tx.Commit().Error; err != nil { + logger.Errorf("[Traffic Stat Queue] Commit transaction failed: %v", err.Error()) + } + } + }(err) + + // 获取全部有效订阅 + var userTraffic []log.UserTraffic + // 获取统计时间范围 + start := time.Date(now.Year(), now.Month(), now.Day()-1, 0, 0, 0, 0, time.Local) + end := start.Add(24 * time.Hour).Add(-time.Nanosecond) + + // 查询用户流量统计, 按用户和订阅分组 + err = tx.WithContext(ctx).Model(&traffic.TrafficLog{}). + Select("user_id, subscribe_id, SUM(download + upload) AS total, SUM(download) AS download, SUM(upload) AS upload"). + Where("timestamp BETWEEN ? AND ?", start, end). + Group("user_id, subscribe_id"). + Order("total DESC"). + Scan(&userTraffic).Error + if err != nil { + logger.Errorf("[Traffic Stat Queue] Query user traffic failed: %v", err.Error()) + return err + } + + date := start.Format(time.DateOnly) + + userTop10 := log.UserTrafficRank{ + Rank: make(map[uint8]log.UserTraffic), + } + + // 更新用户流量统计 + for i, trafficData := range userTraffic { + if i < 10 { + userTop10.Rank[uint8(i+1)] = trafficData + } + // 更新用户流量统计日志 + content, _ := trafficData.Marshal() + err = tx.WithContext(ctx).Model(&log.SystemLog{}).Create(&log.SystemLog{ + Type: log.TypeSubscribeTraffic.Uint8(), + Date: date, + ObjectID: trafficData.SubscribeId, + Content: string(content), + }).Error + if err != nil { + logger.Errorf("[Traffic Stat Queue] Create user traffic log failed: %v", err.Error()) + return err + } + } + + userTop10Content, _ := userTop10.Marshal() + + // 更新用户排行榜 + err = tx.WithContext(ctx).Model(&log.SystemLog{}).Create(&log.SystemLog{ + Type: log.TypeUserTrafficRank.Uint8(), + Date: date, + ObjectID: 0, // 0表示全局用户排行榜 + Content: string(userTop10Content), + }).Error + if err != nil { + logger.Errorf("[Traffic Stat Queue] Create user traffic rank log failed: %v", err.Error()) + return err + } + + // 统计服务器流量 + var serverTraffic []log.ServerTraffic + err = tx.WithContext(ctx).Model(&traffic.TrafficLog{}). + Select("server_id, SUM(download + upload) AS total, SUM(download) AS download, SUM(upload) AS upload"). + Where("timestamp BETWEEN ? AND ?", start, end). + Group("server_id"). + Order("total DESC"). + Scan(&serverTraffic).Error + if err != nil { + logger.Errorf("[Traffic Stat Queue] Query server traffic failed: %v", err.Error()) + return err + } + + serverTop10 := log.ServerTrafficRank{ + Rank: make(map[uint8]log.ServerTraffic), + } + for i, trafficData := range serverTraffic { + if i < 10 { + serverTop10.Rank[uint8(i+1)] = trafficData + } + // 更新服务器流量统计日志 + content, _ := trafficData.Marshal() + err = tx.WithContext(ctx).Model(&log.SystemLog{}).Create(&log.SystemLog{ + Type: log.TypeServerTraffic.Uint8(), + Date: date, + ObjectID: trafficData.ServerId, + Content: string(content), + }).Error + if err != nil { + logger.Errorf("[Traffic Stat Queue] Create server traffic log failed: %v", err.Error()) + return err + } + } + serverTop10Content, _ := serverTop10.Marshal() + // 更新服务器排行榜 + err = tx.WithContext(ctx).Model(&log.SystemLog{}).Create(&log.SystemLog{ + Type: log.TypeServerTrafficRank.Uint8(), + Date: date, + ObjectID: 0, // 0表示全局服务器排行榜 + Content: string(serverTop10Content), + }).Error + if err != nil { + logger.Errorf("[Traffic Stat Queue] Create server traffic rank log failed: %v", err.Error()) + return err + } + + // traffic stat + var stat log.TrafficStat + err = tx.WithContext(ctx).Model(&traffic.TrafficLog{}). + Select("SUM(download + upload) AS total, SUM(download) AS download, SUM(upload) AS upload"). + Where("timestamp BETWEEN ? AND ?", start, end). + Scan(&stat).Error + if err != nil { + logger.Errorf("[Traffic Stat Queue] Query traffic stat failed: %v", err.Error()) + return err + } + + // 更新流量统计日志 + content, _ := stat.Marshal() + err = tx.WithContext(ctx).Model(&log.SystemLog{}).Create(&log.SystemLog{ + Type: log.TypeTrafficStat.Uint8(), + Date: date, + ObjectID: 0, + Content: string(content), + }).Error + if err != nil { + logger.Errorf("[Traffic Stat Queue] Create traffic stat log failed: %v", err.Error()) + return err + } + + // Delete old traffic logs + if l.svc.Config.Log.AutoClear { + err = tx.WithContext(ctx).Model(&traffic.TrafficLog{}).Where("created_at <= ?", end.AddDate(0, 0, int(-l.svc.Config.Log.ClearDays))).Delete(&traffic.TrafficLog{}).Error + if err != nil { + logger.Errorf("[Traffic Stat Queue] Delete server traffic log failed: %v", err.Error()) + } + } + return nil +} diff --git a/queue/logic/traffic/trafficStatisticsLogic.go b/queue/logic/traffic/trafficStatisticsLogic.go index 07509f0..1d3dfa6 100644 --- a/queue/logic/traffic/trafficStatisticsLogic.go +++ b/queue/logic/traffic/trafficStatisticsLogic.go @@ -38,7 +38,7 @@ func (l *TrafficStatisticsLogic) ProcessTask(ctx context.Context, task *asynq.Ta return nil } // query server info - serverInfo, err := l.svc.ServerModel.FindOne(ctx, payload.ServerId) + serverInfo, err := l.svc.NodeModel.FindOneServer(ctx, payload.ServerId) if err != nil { logger.WithContext(ctx).Error("[TrafficStatistics] Find server info failed", logger.Field("serverId", payload.ServerId), @@ -46,23 +46,22 @@ func (l *TrafficStatisticsLogic) ProcessTask(ctx context.Context, task *asynq.Ta ) return nil } - if serverInfo.TrafficRatio == 0 { - logger.WithContext(ctx).Error("[TrafficStatistics] Server log ratio is 0", - logger.Field("serverId", payload.ServerId), - ) - return nil + var serverRatio float32 = 1.0 + if serverInfo.Ratio > 0 { + serverRatio = serverInfo.Ratio } + now := time.Now() realTimeMultiplier := l.svc.NodeMultiplierManager.GetMultiplier(now) for _, log := range payload.Logs { // update user subscribe with log - d := int64(float32(log.Download) * serverInfo.TrafficRatio * realTimeMultiplier) - u := int64(float32(log.Upload) * serverInfo.TrafficRatio * realTimeMultiplier) + d := int64(float32(log.Download) * serverRatio * realTimeMultiplier) + u := int64(float32(log.Upload) * serverRatio * realTimeMultiplier) if err := l.svc.UserModel.UpdateUserSubscribeWithTraffic(ctx, log.SID, d, u); err != nil { logger.WithContext(ctx).Error("[TrafficStatistics] Update user subscribe with log failed", logger.Field("sid", log.SID), - logger.Field("download", float32(log.Download)*serverInfo.TrafficRatio), - logger.Field("upload", float32(log.Upload)*serverInfo.TrafficRatio), + logger.Field("download", float32(log.Download)*serverRatio), + logger.Field("upload", float32(log.Upload)*serverRatio), logger.Field("error", err.Error()), ) continue @@ -88,8 +87,8 @@ func (l *TrafficStatisticsLogic) ProcessTask(ctx context.Context, task *asynq.Ta }); err != nil { logger.WithContext(ctx).Error("[TrafficStatistics] Create log log failed", logger.Field("uid", log.SID), - logger.Field("download", float32(log.Download)*serverInfo.TrafficRatio), - logger.Field("upload", float32(log.Upload)*serverInfo.TrafficRatio), + logger.Field("download", float32(log.Download)*serverRatio), + logger.Field("upload", float32(log.Upload)*serverRatio), logger.Field("error", err.Error()), ) } diff --git a/queue/types/email.go b/queue/types/email.go index c3aa403..4fee979 100644 --- a/queue/types/email.go +++ b/queue/types/email.go @@ -3,15 +3,21 @@ package types const ( // ForthwithSendEmail forthwith send email ForthwithSendEmail = "forthwith:email:send" - // ScheduledBatchSendEmail scheduled batch send email - ScheduledBatchSendEmail = "scheduled:email:batch" +) + +const ( + EmailTypeVerify = "verify" + EmailTypeMaintenance = "maintenance" + EmailTypeExpiration = "expiration" + EmailTypeTrafficExceed = "traffic_exceed" + EmailTypeCustom = "custom" ) type ( SendEmailPayload struct { - Type string `json:"type"` - Email string `json:"to"` - Subject string `json:"subject"` - Content string `json:"content"` + Type string `json:"type"` + Email string `json:"to"` + Subject string `json:"subject"` + Content map[string]interface{} `json:"content"` } ) diff --git a/queue/types/scheduler.go b/queue/types/scheduler.go index 26a32f0..51ef48c 100644 --- a/queue/types/scheduler.go +++ b/queue/types/scheduler.go @@ -4,4 +4,5 @@ const ( SchedulerCheckSubscription = "scheduler:check:subscription" SchedulerTotalServerData = "scheduler:total:server" SchedulerResetTraffic = "scheduler:reset:traffic" + SchedulerTrafficStat = "scheduler:traffic:stat" ) diff --git a/queue/types/sms.go b/queue/types/sms.go index 8d9f9e7..affb521 100644 --- a/queue/types/sms.go +++ b/queue/types/sms.go @@ -1,7 +1,7 @@ package types const ( - // ForthwithSendEmail forthwith send email + // ForthwithSendSms forthwith send email ForthwithSendSms = "forthwith:sms:send" ) diff --git a/queue/types/task.go b/queue/types/task.go new file mode 100644 index 0000000..0115f28 --- /dev/null +++ b/queue/types/task.go @@ -0,0 +1,9 @@ +package types + +const ( + // ScheduledBatchSendEmail scheduled batch send email + ScheduledBatchSendEmail = "scheduled:email:batch" + + // ForthwithQuotaTask create quota task immediately + ForthwithQuotaTask = "forthwith:quota:task" +) diff --git a/scheduler/scheduler.go b/scheduler/scheduler.go index 813f41e..377dca3 100644 --- a/scheduler/scheduler.go +++ b/scheduler/scheduler.go @@ -29,17 +29,23 @@ func (m *Service) Start() { if _, err := m.server.Register("@every 60s", checkTask); err != nil { logger.Errorf("register check subscription task failed: %s", err.Error()) } - // schedule total server data task: every 5 minutes - totalServerDataTask := asynq.NewTask(types.SchedulerTotalServerData, nil) - if _, err := m.server.Register("@every 180s", totalServerDataTask); err != nil { - logger.Errorf("register total server data task failed: %s", err.Error()) - } + //// schedule total server data task: every 5 minutes + //totalServerDataTask := asynq.NewTask(types.SchedulerTotalServerData, nil) + //if _, err := m.server.Register("@every 180s", totalServerDataTask); err != nil { + // logger.Errorf("register total server data task failed: %s", err.Error()) + //} // schedule reset traffic task: every day at 00:30 resetTrafficTask := asynq.NewTask(types.SchedulerResetTraffic, nil) if _, err := m.server.Register("30 0 * * *", resetTrafficTask); err != nil { logger.Errorf("register reset traffic task failed: %s", err.Error()) } + // schedule traffic stat task: every day at 00:00 + trafficStatTask := asynq.NewTask(types.SchedulerTrafficStat, nil) + if _, err := m.server.Register("0 0 * * *", trafficStatTask, asynq.MaxRetry(3)); err != nil { + logger.Errorf("register traffic stat task failed: %s", err.Error()) + } + if err := m.server.Run(); err != nil { logger.Errorf("run scheduler failed: %s", err.Error()) }