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 16import mdns from '@ohos.net.mdns'; 17import DiscoveredPrinter from '../discovery/DiscoveredPrinter'; 18import { Log } from '@ohos/common'; 19import { GlobalThisHelper, GlobalThisStorageKey } from '@ohos/common'; 20import { SERVICE_IPP, SERVICE_IPPS, MDNS_EMITTER_EVENT_ID } from '@ohos/common'; 21import Discovery from './Discovery'; 22import type common from '@ohos.app.ability.common'; 23import CheckEmptyUtils from '@ohos/common'; 24import emitter from '@ohos.events.emitter'; 25import socket from '@ohos.net.socket'; 26import CommonUtils from '../utils/CommonUtils'; 27import uri from '@ohos.uri'; 28import wifi from '@ohos.wifi'; 29 30const TAG = 'MdnsDiscovery'; 31 32export class MdnsDiscovery extends Discovery { 33 34 private readonly _serviceName: string; 35 private _discoveryService: mdns.DiscoveryService; 36 private context: common.ExtensionContext; 37 private resolveEvent: emitter.InnerEvent; 38 39 constructor(scheme: string) { 40 super(); 41 switch (scheme) { 42 case SERVICE_IPP: 43 this._serviceName = SERVICE_IPP; 44 break; 45 case SERVICE_IPPS: 46 this._serviceName = SERVICE_IPPS; 47 break; 48 default: 49 throw new Error('unrecognized scheme ' + scheme); 50 } 51 this.resolveEvent = { eventId: MDNS_EMITTER_EVENT_ID }; 52 emitter.on(this.resolveEvent, this.resolveService); 53 } 54 55 private static toMdnsPrinter(info): DiscoveredPrinter { 56 Log.debug(TAG, 'toMdnsPrinter enter'); 57 if (CheckEmptyUtils.isEmpty(info)) { 58 Log.error(TAG, 'serviceInfo is undefined'); 59 return undefined; 60 } 61 const path = MdnsDiscovery.getServiceAttribute(info, 'rp'); 62 Log.debug(TAG, 'path is: ' + path); 63 if (CheckEmptyUtils.checkStrIsEmpty(path)) { 64 Log.error(TAG, 'rp is missing'); 65 return undefined; 66 } 67 if (path.startsWith('/')) { 68 path === path.substring(1); 69 } 70 const uuid = MdnsDiscovery.getServiceAttribute(info, 'UUID'); 71 const printerId = `mdns://${uuid}`; 72 let printer: DiscoveredPrinter = new DiscoveredPrinter(<string>info.serviceName, printerId, 0, uuid); 73 printer.setUri(<string>info.host.address, <number>info.host.port, path); 74 return printer; 75 } 76 77 private static getServiceAttribute(serviceInfo, key: string): string { 78 const arr = serviceInfo.serviceAttribute; 79 let result = arr.find((attr) => { 80 return attr.key === key; 81 }); 82 if (result === undefined) { 83 Log.error(TAG, `key: ${key}, result is undefined`); 84 return ''; 85 } 86 let value: string = ''; 87 for (let num of result.value) { 88 value += String.fromCharCode(<number>num); 89 } 90 return value; 91 } 92 93 /** 94 * 开始查找打印机 95 */ 96 onStartDiscovery(): void { 97 if (mdns === undefined) { 98 Log.error(TAG, 'mdns is undefined'); 99 return; 100 } 101 Log.info(TAG, 'createDiscoveryService: ' + this._serviceName); 102 this.context = GlobalThisHelper.getValue(GlobalThisStorageKey.KEY_ABILITY_CONTEXT); 103 if (CheckEmptyUtils.isEmpty(this._discoveryService)) { 104 this._discoveryService = mdns.createDiscoveryService(this.context, this._serviceName); 105 } 106 if (this._discoveryService === undefined) { 107 Log.error(TAG, 'discoveryService is undefined'); 108 return; 109 } 110 Log.info(TAG, 'register callback'); 111 this._discoveryService.on('serviceFound', this.onServiceFound); 112 this._discoveryService.on('serviceLost', this.onServiceLost); 113 Log.info(TAG, 'startSearchingMDNS'); 114 this._discoveryService.startSearchingMDNS(); 115 } 116 117 /** 118 * onServiceFound callback 119 */ 120 private onServiceFound = (data): void => { 121 Log.debug(TAG, `onServiceFound, data: ${JSON.stringify(data)} `); 122 emitter.emit(this.resolveEvent, {data: data.serviceInfo}); 123 }; 124 125 private onServiceLost = (data): void => { 126 Log.debug(TAG, `onServiceLost, data: ${CommonUtils.getSecurityPrinterName(data.serviceInfo.serviceName)} `); 127 if (this.mCachePrinters.size === 0) { 128 Log.error(TAG, 'cache printer is empty'); 129 return; 130 } 131 for (let key of this.mCachePrinters.keys()) { 132 if (this.mCachePrinters.get(key).getDeviceName() === data.serviceInfo.serviceName) { 133 this.printerLost(this.mCachePrinters.get(key)?.getPath()); 134 } 135 } 136 }; 137 138 private resolveService = (eventData: emitter.EventData): void => { 139 Log.debug(TAG, 'resolveService enter'); 140 mdns.resolveLocalService(this.context, <mdns.LocalServiceInfo>eventData.data).then((data) => { 141 Log.debug(`${TAG}, resolveLocalService, host is ${CommonUtils.getSecurityIp(data.host.address)}`); 142 if (CheckEmptyUtils.checkStrIsEmpty(data.serviceName)) { 143 Log.info(TAG, 'serviceName is empty'); 144 data.serviceName = eventData.data.serviceName; 145 } 146 let printer = MdnsDiscovery.toMdnsPrinter(data); 147 this.printerFound(printer); 148 }).catch((error) => { 149 Log.error(TAG, `resolveLocalService, err is ${JSON.stringify(error)}`); 150 }); 151 Log.debug(TAG, 'resolveService end'); 152 }; 153 154 /** 155 * 停止搜索打印机,释放所有与搜索相关的资源 156 */ 157 onStopDiscovery(): void { 158 Log.info(TAG, 'onStopDiscovery enter'); 159 if (this._discoveryService === undefined) { 160 Log.info(TAG, 'discoveryService is undefined'); 161 return; 162 } 163 this._discoveryService.stopSearchingMDNS(); 164 } 165}