1/* 2 * Copyright (c) 2023-2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16// @ts-ignore 17import mdns from '@ohos.net.mdns'; 18import DiscoveredPrinter from '../discovery/DiscoveredPrinter'; 19import { Log } from '@ohos/common'; 20import { GlobalThisHelper, GlobalThisStorageKey } from '@ohos/common'; 21import { SERVICE_IPP, SERVICE_IPPS, MDNS_EMITTER_EVENT_ID } from '@ohos/common'; 22import Discovery from './Discovery'; 23import type common from '@ohos.app.ability.common'; 24import CheckEmptyUtils from '@ohos/common'; 25import emitter from '@ohos.events.emitter'; 26import socket from '@ohos.net.socket'; 27import CommonUtils from '../utils/CommonUtils'; 28import uri from '@ohos.uri'; 29import wifi from '@ohos.wifi'; 30 31const TAG = 'MdnsDiscovery'; 32 33export class MdnsDiscovery extends Discovery { 34 35 private readonly _serviceName: string; 36 private _discoveryService: mdns.DiscoveryService; 37 private context: common.ExtensionContext; 38 private resolveEvent: emitter.InnerEvent; 39 40 constructor(scheme: string) { 41 super(); 42 switch (scheme) { 43 case SERVICE_IPP: 44 this._serviceName = SERVICE_IPP; 45 break; 46 case SERVICE_IPPS: 47 this._serviceName = SERVICE_IPPS; 48 break; 49 default: 50 throw new Error('unrecognized scheme ' + scheme); 51 } 52 this.resolveEvent = { eventId: MDNS_EMITTER_EVENT_ID }; 53 emitter.on(this.resolveEvent, this.resolveService); 54 } 55 56 private static toMdnsPrinter(info): DiscoveredPrinter { 57 Log.debug(TAG, 'toMdnsPrinter enter'); 58 if (CheckEmptyUtils.isEmpty(info)) { 59 Log.error(TAG, 'serviceInfo is undefined'); 60 return undefined; 61 } 62 const path = MdnsDiscovery.getServiceAttribute(info, 'rp'); 63 Log.debug(TAG, 'path is: ' + path); 64 if (CheckEmptyUtils.checkStrIsEmpty(path)) { 65 Log.error(TAG, 'rp is missing'); 66 return undefined; 67 } 68 if (path.startsWith('/')) { 69 path === path.substring(1); 70 } 71 const uuid = MdnsDiscovery.getServiceAttribute(info, 'UUID'); 72 Log.debug(TAG, 'uuid is: ' + uuid); 73 const printerId = `mdns://${uuid}`; 74 let printer: DiscoveredPrinter = new DiscoveredPrinter(<string>info.serviceName, printerId, 0, uuid); 75 Log.debug(TAG, 'host is: ' + JSON.stringify(info.host)); 76 printer.setUri(<string>info.host.address, <number>info.host.port, path); 77 return printer; 78 } 79 80 private static getServiceAttribute(serviceInfo, key: string): string { 81 const arr = serviceInfo.serviceAttribute; 82 let result = arr.find((attr) => { 83 return attr.key === key; 84 }); 85 if (result === undefined) { 86 Log.error(TAG, `key: ${key}, result is undefined`); 87 return ''; 88 } 89 let value: string = ''; 90 for (let num of result.value) { 91 value += String.fromCharCode(<number>num); 92 } 93 return value; 94 } 95 96 /** 97 * 开始查找打印机 98 */ 99 onStartDiscovery(): void { 100 if (mdns === undefined) { 101 Log.error(TAG, 'mdns is undefined'); 102 return; 103 } 104 Log.info(TAG, 'createDiscoveryService: ' + this._serviceName); 105 this.context = GlobalThisHelper.getValue(GlobalThisStorageKey.KEY_ABILITY_CONTEXT); 106 if (CheckEmptyUtils.isEmpty(this._discoveryService)) { 107 this._discoveryService = mdns.createDiscoveryService(this.context, this._serviceName); 108 } 109 if (this._discoveryService === undefined) { 110 Log.error(TAG, 'discoveryService is undefined'); 111 return; 112 } 113 Log.info(TAG, 'register callback'); 114 this._discoveryService.on('serviceFound', this.onServiceFound); 115 this._discoveryService.on('serviceLost', this.onServiceLost); 116 Log.info(TAG, 'startSearchingMDNS'); 117 this._discoveryService.startSearchingMDNS(); 118 } 119 120 /** 121 * onServiceFound callback 122 */ 123 private onServiceFound = (data): void => { 124 Log.debug(TAG, `onServiceFound, data: ${JSON.stringify(data)} `); 125 emitter.emit(this.resolveEvent, {data: data.serviceInfo}); 126 }; 127 128 private onServiceLost = (data): void => { 129 Log.debug(TAG, `onServiceLost, data: ${CommonUtils.getSecurityPrinterName(data.serviceInfo.serviceName)} `); 130 if (this.mCachePrinters.size === 0) { 131 Log.error(TAG, 'cache printer is empty'); 132 return; 133 } 134 for (let key of this.mCachePrinters.keys()) { 135 if (this.mCachePrinters.get(key).getDeviceName() === data.serviceInfo.serviceName) { 136 this.printerLost(this.mCachePrinters.get(key)?.getPath()); 137 } 138 } 139 }; 140 141 private resolveService = (eventData: emitter.EventData): void => { 142 Log.debug(TAG, 'resolveService enter'); 143 mdns.resolveLocalService(this.context, <mdns.LocalServiceInfo>eventData.data).then((data) => { 144 Log.debug(`${TAG}, resolveLocalService, host is ${CommonUtils.getSecurityIp(data.host.address)}`); 145 if (CheckEmptyUtils.checkStrIsEmpty(data.serviceName)) { 146 Log.info(TAG, 'serviceName is empty'); 147 data.serviceName = eventData.data.serviceName; 148 } 149 let printer = MdnsDiscovery.toMdnsPrinter(data); 150 this.printerFound(printer); 151 }).catch((error) => { 152 Log.error(TAG, `resolveLocalService, err is ${JSON.stringify(error)}`); 153 }); 154 Log.debug(TAG, 'resolveService end'); 155 }; 156 157 /** 158 * 停止搜索打印机,释放所有与搜索相关的资源 159 */ 160 onStopDiscovery(): void { 161 Log.info(TAG, 'onStopDiscovery enter'); 162 if (this._discoveryService === undefined) { 163 Log.info(TAG, 'discoveryService is undefined'); 164 return; 165 } 166 this._discoveryService.stopSearchingMDNS(); 167 } 168}